Xamarin Android throws IOException when using ZipFile.ExtractToDirectory method - c#

I try to use the following code in my project without any success and it's driving me mad.
System.IO.Compression.ZipFile.ExtractToDirectory(filePath, appPath);
The parameters are:
filePath = "/storage/emulated/0/Flashback_Backup/memory_backup.zip"
appPath = "/storage/emulated/0/Flashback"
According to the documentation here IOException should be thrown if:
The directory specified by destinationDirectoryName already exists.
-or- The name of an entry in the archive is Empty, contains only white space, or contains at least one invalid character.
-or- Extracting an archive entry would create a file that is outside the directory specified by destinationDirectoryName. (For example,
this might happen if the entry name contains parent directory
accessors.)
-or- An archive entry to extract has the same name as an entry that has already been extracted from the same archive.
As far as I know none of it applies. The zip file is a totally valid one, which I compressed with the Directory.CreateDirectory method, and only contains a few uniquely named JSON files. I tried with and without existing "Flashback" folder too, but nothing seems to work.
If anyone have any ideas or solutions please tell me because I'm seriously lost at this. I can provide more info if needed.

Try to wrap extraction intro try-catch, it may give you a better understanding of what is going on.
try {
System.IO.Compression.ZipFile.ExtractToDirectory(filePath, appPath);
} catch (Exception ex) {
Console.Log(ex);
}
If there is an error, it will be one of your listed above.

Related

Why do I need to Set File Attributes C#?

Hi I am new to C# and I am reviewing a code I didn't write. The code copies a compressed file from a network location to a local location before it is extracted and then parsed for data. The copy file function is:
public static void CopySourceFileToDestinationFile(string sourcePath, string destinationPath)
{
try
{
//copy log from source to local and uncompress it
File.Copy(sourcePath, destinationPath, true);
File.SetAttributes(destinationPath, FileAttributes.Normal);
}
catch (Exception ex)
{
var errmsg = $"ERROR in function 'CopySourceFileToDestinationFile()': {ex.Message.ToString()}";
Logger.Error(errmsg);
throw new InvalidOperationException(errmsg);
}
}
I see the File.SetAttributes function and looked up it and all it said on https://learn.microsoft.com/en-us/dotnet/api/system.io.file.setattributes?view=net-5.0 was telling me what the function is but not why you'd need it.
So I humbly ask, why do I ever need to use this function? Had I written this code from scratch I wouldn't have known the existence of this function, nor it's purpose
If you were reviewing that code, what I'd be more curious about is why the original developer put a lying comment above the copy action (it doesn't decompress) and why they catch an exception only to log and throw its message (why not the exception type and its stack trace)?
But about the attributes: a file, when written, will get an Archive flag, indicating to backup software that the file should be backed up. Clearing this bit by setting the file's attributes to Normal (i.e. no attributes) will ... probably not be very relevant, unless this file is copied into a directory that will actually be backed up.
It's not very relevant as any decent backup program won't just look at the Archive bit to decide whether to include a file in its backup or not. Clearing this attribute, as well as the rest of the code, reeks like code smell, cargo cult, voodoo programming and whatnot.

How to copy files from one disk to another location with the same folder structure?

I want to make an exact copy of some files, directories and subdirectories that are on my USB drive I:/ and want them to be in C:/backup (for example)
My USB drive has the following structure:
(just to know, this is an example, my drive has more files, directories and subdirectories)
courses/data_structures/db.sql
games/pc/pc-game.exe
exams/exam01.doc
Well, I am not sure how to start with this but my first idea is to get all the files doing this:
string[] files = Directory.GetFiles("I:");
The next step could be to make a loop and use File.Copy specifying the destination path:
string destinationPath = #"C:/backup";
foreach (string file in files)
{
File.Copy(file, destinationPath + "\\" + Path.GetFileName(file), true);
}
At this point everything works good but not as I wanted cause this doesn't replicate the folder structure. Also some errors happen like the following...
The first one happens because my PC configuration shows hidden files for every folder and my USB has an AUTORUN.INF hidden file that is not hidden anymore and the loop tries to copy it and in the process generates this exception:
Access to the path 'AUTORUN.INF' is denied.
The second one happens when some paths are too long and this generates the following exception:
The specified path, file name, or both are too long. The fully
qualified file name must be less than 260 characters, and the
directory name must be less than 248 characters.
So, I am not sure how to achieve this and validate each posible case of error. I would like to know if there is another way to do this and how (maybe some library) or something more simple like an implemented method with the following structure:
File.CopyDrive(driveLetter, destinationFolder)
(VB.NET answers will be accepted too).
Thanks in advance.
public static void Copy(string src, string dest)
{
// copy all files
foreach (string file in Directory.GetFiles(src))
{
try
{
File.Copy(file, Path.Combine(dest, Path.GetFileName(file)));
}
catch (PathTooLongException)
{
}
// catch any other exception that you want.
// List of possible exceptions here: http://msdn.microsoft.com/en-us/library/c6cfw35a.aspx
}
// go recursive on directories
foreach (string dir in Directory.GetDirectories(src))
{
// First create directory...
// Instead of new DirectoryInfo(dir).Name, you can use any other way to get the dir name,
// but not Path.GetDirectoryName, since it returns full dir name.
string destSubDir = Path.Combine(dest, new DirectoryInfo(dir).Name);
Directory.CreateDirectory(destSubDir);
// and then go recursive
Copy(dir, destSubDir);
}
}
And then you can call it:
Copy(#"I:\", #"C:\Backup");
Didn't have time to test it, but i hope you get the idea...
edit: in the code above, there are no checks like Directory.Exists and such, you might add those if the directory structure of some kind exists at destination path. And if you're trying to create some kind of simple sync app, then it gets a bit harder, as you need to delete or take other action on files/folders that don't exist anymore.
This generally starts with a recursive descent parser. Here is a good example: http://msdn.microsoft.com/en-us/library/bb762914.aspx
You might want to look into the overloaded CopyDirectory Class
CopyDirectory(String, String, UIOption, UICancelOption)
It will recurse through all of the subdirectories.
If you want a standalone application, I have written an application that copies from one selected directory to another, overwriting newer files and adding subdirectories as needed.
Just email me.

File Copy - Keep both files if name conflicts

File.Copy allows simple file copying. When a duplicate file name is encountered, File.Copy has a third parameter to determine if the original file is overwritten or not.
Is there a built-in .Net function that allows a third option to rename the copied file and hence keep both files?. For example, the file copy would automatically rename "readme.txt" to "readme - Copy.txt" if another readme.txt already existed in the destination folder - similar to Windows Explorer functionality?
I realize it can be written but didn't want reinvent the wheel if it exists.
Thanks in advance.
Nope, this functionality doesn't exist out of the box (thankfully, as it would introduce a responsibility to the framework which it ought not to have*,) so if you want this, then you will need to implement a bespoke solution.
*Which implementation should it take? Appending "- Copy", appending "(n)"? It becomes problematic rather sherpish.
There's nothing you can do all-in-one go with File.Copy, however you could test if the destination exists and then Move instead.
Move takes two parameters, and you can essentially rename at the same time.
if File.Exists(destinationPath) {
File.Move(source, destinationPathRenamed);
} else {
try {
File.Copy(source, destinationPath);
} catch (IOException ex) {
// destinationPath file already exists
File.Move(source, destinationPathRenamed);
}
}
See Move documentation
EDIT:
Updated code above. #xanatos makes a good point about atomic operation. I made no assumptions about whether there are other processes accessing the file(s).
Note that I haven't added other error handling for the source file being deleted before the operation begins either.
var destinationPath = c:\temp\archive.txt;
if(File.Exists(destinationPath))
destinationPath = string.Format("c:\temp\archive.{0}.txt", DateTime.Now.ToString("yyyyMMddHHmmffff"));
File.Move(filePath, destinationPath );

UnauthorizedAccessException on newly created files

I have an application that is looking through some files for old data. In order to make sure we don't corrupt good projects, I'm copying the files to a temporary location. Some of the directories I'm checking are source-code directories, and they have .svn folders. We use Subversion to manage our code.
Once I've searched through all of the files, I want to delete the temp cache. Sounds easy, right?
For some reason, all of my .svn directories won't delete from the cache. They crash the app.
For reasons (too deep to go into here), I have to use the temp folder, so just "scan the original file" is out of the question for political reasons.
I can go into explorer and delete them. No problem. No warnings. Just deletes. But the code crashes with "Access to {file} is denied." I'm at my wits end with this one, so any help would be appreciated.
While I've simplified the function a LITTLE for sake of your sanity, the code REALLY is about this simple.
List<string> tmpCacheManifest = new List<string>();
string oldRootPath = "C:\\some\\known\\directory\\";
string tempPath = "C:\\temp\\cache\\";
foreach (string file in ListOfFilesToScan)
{
string newFile = file.Replace(oldRootPath, tempPath);
// This works just fine.
File.Copy(file, newFile);
tmpCacheManifest.add(newFile);
}
// ... do some stuff to the cache to verify what I need.
// Okay.. I'm done.. Delete the cache.
foreach (string file in tmpCacheManifest)
{
// CRASH!
File.Delete(file);
}
* Update *: The exception is UnauthorizedAccessException. The text is "Access to the path 'C:\temp\cache\some-sub-dirs\.svn\entries' is denied."
It happens under XP, XP-Pro and Windows 7.
* Update 2 * None of my validation even ATTEMPTS to look at subversion files. I do need them, however. That's part of the political crap. I have to show that EVERY file was copied... wheter it was scanned or not.
And I realize what the usual suspects are for File.Delete. I realize what UnauthorizedAccessException means. I don't have access. That's a no-brainer. But I just copied the file. How can I NOT have access to the file?
* Update 3 *
The answer was in the "read-only" flag. Here's the code I used to fix it:
foreach (string file in ListOfFilesToScan)
{
string newFile = file.Replace(oldRootPath, tempPath);
// This works just fine.
File.Copy(file, newFile);
//// NEW CODE ////
// Clear any "Read-Only" flags
FileInfo fi3 = new FileInfo(fn);
if ((fi3.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
{
fi3.Attributes = (FileAttributes)(Convert.ToInt32(fi3.Attributes) - Convert.ToInt32(FileAttributes.ReadOnly));
}
tmpCacheManifest.add(newFile);
}
// ... do some stuff to the cache to verify what I need.
As far as I recall, Subversion marks the files in its .svn subdirectories as read-only.
Try resetting the read-only attribute before deleting the file. I don't really know any C#, but a quick Google suggests this might do the trick:
File.SetAttributes(file, FileAttributes.Normal);
The only problem I see would be in this part:
// ... do some stuff to the cache to verify what I need.
If you do open the file and forget to close it, you still have exclusive access to it, and thus can't delete it later on.
Sounds like you don't have access to delete the file...
system.io.file.delete
The above link says you get UnauthorizedAccessException when:
The caller does not have the required permission.
-or-
path is a directory.
-or-
path specified a read-only file.
It's one of those.
Sounds like a permissions issue. Tricky one though as you obviously have write access if the File.Copy already works....
Only thing I could think of is the file still has a handle opened somewhere (as others have suggested perhaps in your do some stuff to the cache part).
First of all: "Crash" means an exception, right? Which one? Can you catch it and show it?
Second thing: You are copying subversion repositories, although you don't care about the subversion metadata? That's what svn export is about (no .svn directory in the target).
The answer to the first question is what you really need to provide. Maybe something grabs the .svn and locks some files. TortoiseSVN maybe (to give you nice overlay icons..)?
If a folder contains read only files, Directory.Delete won't delete it and raise the exception you're getting. For future visitors of this page, I've found a simple solution which doesn't require us to recurse through all the files and changing their read-only attribute:
Process.Start("cmd.exe", "/c " + #"rmdir /s/q C:\Test\TestDirectoryContainingReadOnlyFiles");
(Change a bit to not to fire a cmd window momentarily, which is available all over the internet)
Not understanding what you want to do so much, but what about chmoding it to 777 or 775. :-/
Edit:
Noticed your on windows. You'd have to change the permissions. Don't know how windows does that :-/

File not found Exception.. But it's there

Hey this is going to be one of those dumb questions. I am trying to pick up a file on my local system and I keep getting a FileNotFoundException thrown.
Someone set me straight please :)
if( File.Exists(#"C:\logs\hw-healthways-prod_2009-08-26.tar"))
{
Console.WriteLine("Yay");
}
else
{
throw new FileNotFoundException();
}
Tried moving the file into the same location as the executing application and did the following:
if( File.Exists("hw-healthways-prod_2009-08-26.tar"))
Same thing.
Then I made a random txt file and parked it there too.. "me.txt"
And it works?! So you thing the file name is the problem?
Try doing Directory.GetFiles(#"C:\logs"). It's possible that the file in question has odd characters that are getting interpreted one way by Windows Explorer (presumably where you're reading "the file's property" from?) but a different way by the .NET Framework. This can happen if you have UTF-8 characters in the filename (perhaps an en dash?).
May be the name of the file is "hw-healthways-prod_2009-08-26.tar.tar" instead of "hw-healthways-prod_2009-08-26.tar", I had this problem because by default the extension files are hidden on windows
You may want to check your file permissions. Your computer may not have permission to the file.
C:\logs\hw-healthways-prod_2009-08-26.tar should be C:\\logs\\hw-healthways-prod_2009-08-26.tar. \ means the next character is an escape character.

Categories