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

Hi Folks, I need to remove the COMPRESSED attribute on a number of files. I can find those files using Win32::File::GetAttributes, but how can I remove it using SetAttributes?
Win32::File::GetAttributes($path, $attr); if ($attr & COMPRESSED) { print "File is compressed\n"; # Here I will remove the compressed attribute, but how? }
Must I capture the existing attributes and then apply all but the COMPRESSED one using SetAttributes? Some example code would be great. I've searched the internets with no success. Thanks - Tim

Replies are listed 'Best First'.
Re: How to remove COMPRESSED attribute with Win32::File?
by ikegami (Patriarch) on Mar 06, 2009 at 01:51 UTC
    On:
    Win32::File::GetAttributes($path, $attr); $attr |= COMPRESSED; Win32::File::SetAttributes($path, $attr);
    Off:
    Win32::File::GetAttributes($path, $attr); $attr &= ~COMPRESSED; Win32::File::SetAttributes($path, $attr);
Re: How to remove COMPRESSED attribute with Win32::File?
by almut (Canon) on Mar 06, 2009 at 01:50 UTC

    I suppose you'll need to remove just the COMPRESSED bit, and leave the rest of $attr as it is:

    ... $attr &= ~COMPRESSED; Win32::File::SetAttributes($path, $attr);

    BTW, for instructive purposes, you can visualize the bits with

    print unpack("B*", pack("N", $attr)), "\n"; # or printf "%032b\n", $attr;
Re: How to remove COMPRESSED attribute with Win32::File?
by BrowserUk (Patriarch) on Mar 06, 2009 at 06:42 UTC
      Thanks to everyone - I now have the solution! I can detect comporession using Win32::File, then remove it using compact /u . Tim

        Did you notice that compact can take a wildcard?

        If you give it a directory name it will operate on all the files in that directory in one go which would be far quicker than discovering the files yourself and then calling the command for each file individually.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: How to remove COMPRESSED attribute with Win32::File?
by lostjimmy (Chaplain) on Mar 06, 2009 at 02:06 UTC

    And just in case you want a bit of explanation...

    In order to clear a bit, you must first negate the bit mask, then bitwise AND it with the attribute flags. So the negation flips the bits, which makes it all ones, except for the bit we want to clear. This way when you AND it with the flags, the only bit affected is the one we want to clear.

    That was wordy and probably confusing. I guess that's what I get for posting at 2:00am. How about an example?

    #These values probably don't match the actual values COMPRESSED = 0001 0000 $attr = 0101 1100 After negation = 1110 1111 &0101 1100 ---------- 0100 1100
      Thank you for the replies. I tried the following without success:
      use Win32::File; my $path="C:\\temp\\Perl\\TestFolder\\TestFile.txt"; my $attr; Win32::File::GetAttributes($path, $attr); if ($attr & COMPRESSED) { print "File is compressed. Now uncompress it!\n"; $attr &= ~COMPRESSED; Win32::File::SetAttributes($path, $attr); } else { print "File is not compressed. Nothing to do here.\n"; }
      Any ideas on what I am doing wrong? I can set and unset the attribute in Windows Explorer but with the Perl code compression remains on. Cheers, Tim

        My first thought was:

        Maybe if you checked for errors, you'd know? The docs state how to detect if an error occured. And when one does, you can probably find out the error from $^E.

        But it seems SetFileAttributes, the system call for which Win32::File::SetAttributes is a wrapper, simply ignores the flag.

        The documentation directs programmers to "use the DeviceIoControl function with the FSCTL_SET_COMPRESSION operation."

        Any ideas on what I am doing wrong?

        I don't think you can change the 'COMPRESSED' status of a file using Win32::File. The MSDN documentation I'm looking at says that SetFileAttributes (which is what Win32::File is using) is unable to set the compression attribute - and I suspect that it is likewise unable to turn that attribute off. At least, I can't get the script that you posted to do the right thing, either - and it's not throwing any errors.

        Cheers,
        Rob