http://www.perlmonks.org?node_id=530964

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks!
I am trying to read some file(s), get its size, and if the file(s) are larger than what I've declared in the variable $last_maxsize, delete over sized file content until it reaches the size specified. For some reason the code is deleting all the lines in the file(s) but the first line, the number in the $last_maxsize variable is just been ignored, can anyone help me on that?
Here is the piece of code doing that:

my $last_maxsize = 170000; #I need to delete original files here... open my $last_in, '<', "$path_only/$file_name" or die $!; { local $/ = \$last_maxsize; while ( my $new_record = <$last_in> ) { next if -s $new_record > $last_maxsize; open my $last_out, '>', "$path_only/$file_name" or die $ +!; #It should create the file(s) with a new size print $last_out $new_record; close $last_out or die $!; } close $last_in; }


Thanks a lot!

Replies are listed 'Best First'.
Re: Delete On File Size
by Fletch (Bishop) on Feb 17, 2006 at 15:55 UTC

    You're attempting to simultaneously read and write to the same file. That's not going to work real well. What you need to do is something along the lines of

    • open the original file and seek to the end
    • seek backwards the amount of data you want to keep (probably seeking back further and then reading forward to find the next full line/record; or use something like Tie::File)
    • read those lines and write them into a new temporary file
    • rename the temporary file to the original file's name
Re: Delete On File Size
by mikeock (Hermit) on Feb 17, 2006 at 15:50 UTC
    Here is a snippet that does somewhat the same thing
    BEGIN{require Win32::Console;Win32::Console::Free() if ($^O eq "MSWin3 +2");} #sets file to remove my $file = "puk.log"; # Removes file if file exists and file is larger than 200k unlink "$file" if(-e $file and -s $file > 200000);
    I have it set as a scheduled task that is why the Win32::Console::Free() is there

    This is in the same directory as the file I want to delete. I set the filesuze to 2mb so that it does not get unruly and just remove it!

    edit: Woops apparently I did not read what you needed before posting but hey it might be usefull to someone

      What if you want to keep the remaning of it, how would you do it?
        Look at the post below. It has the details that you are looking for!
Re: Delete On File Size
by wulvrine (Friar) on Feb 17, 2006 at 17:20 UTC
    You could read and write to different files. Then when the pruning has finished, the new file is the file size you want. Unlink the first file and move the second over into the first files spot. However, just a question on the logic, you are creating some generic file. Then at a later date are checking its filesize. If it is greater than size X, prune the file to size X (be careful which part of the file you desire to keep, the beginning or the end). At this point, your file is sixe X, already, which means the next change to that file will push it to over size. Wouldn't it be better to prune it smaller than the limit's size, rather than a size thats already over the next runs limit?
Re: Delete On File Size
by graff (Chancellor) on Feb 18, 2006 at 16:09 UTC
    I am trying to read some file(s), get its size, and if the file(s) are larger than ...

    I think you want to change the order of the operations: get the file size first, then if it's bigger than $last_maxsize, open it, read $last_maxsize bytes, write that to a new version of the file:

    if ( -s "$path_only/$file_name" > $last_maxsize ) { local $/ = \$last_maxsize; open IN, '<', "$path_only/$file_name"; $_ = <IN>; close IN; open OUT, '>', "$path_only/$file_name"; print OUT; close OUT; }

    Looking at the code you posted, I was puzzled by this part:

    while ( my $new_record = <$last_in> ) { next if -s $new_record > $last_maxsize; ...
    Look up "perldoc -f -X" to read about the "-s" function -- it takes either a file handle or the name of a file. Since $new_record is neither of these things in your code, I would expect "-s" to always return 0. And since this is never greater than $last_maxsize, you will be opening an output file every time. And why use a while loop at all, if you only intend to read a single record of $last_maxize bytes?

    The last issue, of course, it whether it's really wise to always truncate the file to a specific number of bytes. If it's text data, you might want to respect line boundaries (or at least word boundaries) -- and if the text is in some non-ASCII encoding (e.g. has utf8 wide characters) you should be sure to respect character boundaries; if it's compressed data, truncating it at all will make it impossible to uncompress; and so on... It's actually hard to imagine any kind of data that wouldn't suffer badly from an arbitrary fixed-length truncation like this.