An item with the same key has already been added Ionic.Zip - c#

Good afternoon, please tell me how can I add files with the same name to the archive? To be like copying, the file becomes file(1).* and there are two files file and file(1) . I am using Ionic.Zip
string BackupDir = #"C:\Users\Desktop\dir\backup.zip";
string PathToFolder = #"C:\Users\Desktop\dir";
string[] AllFiles = Directory.GetFiles(PathToFolder, "*.*", SearchOption.AllDirectories);
using (ZipFile zip = new ZipFile(BackupDir, Encoding.UTF8))
{
foreach (string file in AllFiles)
{
try
{
DateTime FileCreationTime = File.GetCreationTime(file);
if (FileCreationTime >= DateTime.Now - new TimeSpan(60, 0, 0, 0))
{
Console.WriteLine(file);
zip.CompressionLevel = Ionic.Zlib.CompressionLevel.BestSpeed;
zip.AddFile(file, "");
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
zip.Save(BackupDir);
}
}

Try this:
//keep track of fileNames
var fileNames = new HashSet<string>(StringCompaer.OridialIgnoreCase);
foreach (string file in AllFiles)
{
try
{
DateTime FileCreationTime = File.GetCreationTime(file);
if (FileCreationTime >= DateTime.Now - new TimeSpan(60, 0, 0, 0))
{
Console.WriteLine(file);
zip.CompressionLevel = Ionic.Zlib.CompressionLevel.BestSpeed;
var fileName = Path.GetFileName(file);
if (fileNames.Add(fileName))
zip.AddFile(file, ""); //fileName could be added to fileNames = it is unique
else
{
//start with 1
int counter = 1;
//loop till you found a fileName thats not occupied
while (true)
{
//build the new file name
var newFileName = $"{Path.GetFileNameWithoutExtension(fileName)} - {counter}{Path.GetExtension(fileName}";
if (fileNames.Add(newFileName))
{
fileName = newFileName; //use the new fileName
break; //break the loop
}
//increase counter if newFileName is already in the list fileNames
counter++;
}
var zipFileEntry = zip.AddFile(file, "");
zipFileEntry.FileName = fileName;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
zip.Save(BackupDir);
}

Check if file exists and add suffix to it's name.
Something like (Pseudocode):
int nameCount = 1;
fileName = file.Name;
while(fileName exists in archive)
{
nameCount++;
fileName = file.Name + "_" + nameCount;
}

Related

Get files from a folder that I have created in Xamarin.Android

I want get all files from an external storage folder(wall_e_imgs)..Here are codes-
public void getImages()
{
var path1 = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath.ToString();
string path = System.IO.Path.Combine(path1, "wall_e_imgs");
//var files= System.IO.Directory.GetFiles(Android.OS.Environment.ExternalStorageDirectory.ToString() + "wall_e_imgs");
//var files = System.IO.Directory.GetFiles(path);
//string path = Android.OS.Environment.ExternalStorageDirectory.ToString() + "/wall_e_imgs";
//File directory=new File(path);
Java.IO.File directory = new Java.IO.File(path);
Java.IO.File[] files = directory.ListFiles();//always count is 0 even though there are lot files there
foreach (var i in files)
{
FileInfo info = new FileInfo(i.Name);
if (info.Name.Contains("Wall_e"))
{
di.Add(new DownloadedImages { Path1 = info.DirectoryName, Name1 = info.FullName });
}
}
}
But it always give 0 files even though there are lot of files.
Try this
var folder = Android.OS.Environment.ExternalStorageDirectory + Java.IO.File.Separator + "yourfoldername";
if (!Directory.Exists(folder))
Directory.CreateDirectory(folder);
var filesList = Directory.GetFiles(folder);
foreach (var file in filesList)
{
var filename = Path.GetFileName(file);
}
Try something like this:
// Use whatever folder path you want here, the special folder is just an example
string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "wall_e_imgs");
if (Directory.Exists(folderPath))
{
var files = Directory.EnumerateFiles(folderPath);
foreach (var file in files)
{
// Do your stuff
}
}
Please note that this uses the Directory class from System.IO, not Java.IO
ffilelist will contain a list of mp3 files in "/storage/emulated/0/Music/"
string phyle;
string ffilelist = "";
public void listfiles()
{
try
{
var path1 = "/storage/emulated/0/Music/";
var mp3Files = Directory.EnumerateFiles(path1, "*.mp3", SearchOption.AllDirectories);
foreach (string currentFile in mp3Files)
{
phyle = currentFile;
ffilelist = ffilelist + "\n" + phyle;
}
//playpath(phyle); // play the last file found
}
catch (Exception e9)
{
Toast.MakeText(ApplicationContext, "ut oh\n"+e9.Message , ToastLength.Long).Show();
}
}

Copy file code?

I need a copy file on folder to another folder and i'm use this
string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath);
foreach (string file in files)
{
folderBrowserDialog1.ShowDialog();
string xx = folderBrowserDialog1.SelectedPath;
folderBrowserDialog1.ShowDialog();
string yy = folderBrowserDialog1.SelectedPath;
File.Copy(xx, yy);
But is not working.
Why?
Try this code.
I assume you want to read a file then write it to new one.
Hope it helps.
string sourceFile;
string newFile = "C:\NewFile\NewFile.txt";
string fileToRead = "C:\ReadFile\ReadFile.txt";
bool overwriteExistingFile = true; //change to false if you want no to overwrite the existing file.
bool isReadSuccess = getDataFromFile(fileToRead, ref sourceFile);
if (isReadSuccess)
{
File.Copy(sourceFile, newFile, overwriteExistingFile);
}
else
{
Console.WriteLine("An error occured :" + sourceFile);
}
//Reader Method you can use this or modify it depending on your needs.
public static bool getDataFromFile(string FileToRead, ref string readMessage)
{
try
{
readMessage = "";
if (!File.Exists(FileToRead))
{
readMessage = "File not found: " + FileToRead;
return false;
}
using (StreamReader r = new StreamReader(FileToRead))
{
readMessage = r.ReadToEnd();
}
return true;
}
catch (Exception ex)
{
readMessage = ex.Message;
return false;
}
}
It seems that you do not use filenames in your source code.
I made an example. File copy function.
public void SaveStockInfoToAnotherFile(string sPath, string dPath, string filename)
{
string sourcePath = sPath;
string destinationPath = dPath;
string sourceFile = System.IO.Path.Combine(sourcePath, filename);
string destinationFile = System.IO.Path.Combine(destinationPath, filename);
if (!System.IO.Directory.Exists(destinationPath))
{
System.IO.Directory.CreateDirectory(destinationPath);
}
System.IO.File.Copy(sourceFile, destinationFile, true);
}
//folderBrowserDialog1.ShowDialog();
//string xx = folderBrowserDialog1.SelectedPath;
//string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath);
//folderBrowserDialog1.ShowDialog();
//string yy = folderBrowserDialog1.SelectedPath;
//foreach (string file in files)
//{
// File.Copy(xx + "\\" + Path.GetFileName(file), yy + "\\" + Path.GetFileName(file));

Reading large number of text files using task (TPL)

I am reading around 300 txt files using the task concept. My requirement is to read each file , pick the date from every line , check in which week it comes and then compare it with the folder name which are actually the week names (like 41 , 42) whether they both are same or not. if not then write that file name and the line number. As the number of files and the size of files is huge , I am trying to use task concept to that I can speed up the process. Below is my code.
Any help would be appreciated. Thanks in advance.
private void browse_Click(object sender, EventArgs e)
{
try
{
string newFileName = "";
DialogResult result = folderBrowserDialog1.ShowDialog();
if (result == DialogResult.OK)
{
DateTime starttime = DateTime.Now;
string folderPath = Path.GetDirectoryName(folderBrowserDialog1.SelectedPath);
DirectoryInfo dInfo = new DirectoryInfo(folderPath);
string[] Allfiles = Directory.EnumerateFiles(folderPath, "*.txt", SearchOption.AllDirectories).ToArray();
foreach (DirectoryInfo folder in dInfo.GetDirectories())
{
newFileName = "Files_with_duplicate_TGMKT_Names_in_child_Folder_" + folder.Name + ".txt";
if (File.Exists(folderPath + "/" + newFileName))
{
File.Delete(folderPath + "/" + newFileName);
}
FileInfo[] folderFiles = folder.GetFiles();
if (folderFiles.Length != 0)
{
List<Task> tasks = new List<Task>();
foreach (var file in folderFiles)
{
var task = Task.Factory.StartNew(() =>
{
bool taskResult = ReadFile(file.FullName,folderPath,newFileName);
return taskResult;
});
tasks.Add(task);
}
Task.WaitAll(tasks.ToArray());
DateTime stoptime = DateTime.Now;
TimeSpan totaltime = stoptime.Subtract(starttime);
label6.Text = Convert.ToString(totaltime);
textBox1.Text = folderPath;
DialogResult result2 = MessageBox.Show("Read the files successfully.", "Important message", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
}
catch (Exception)
{
throw;
}
}
public bool ReadFile(string file , string folderPath , string newFileName)
{
int LineCount = 0;
string fileName = Path.GetFileNameWithoutExtension(file);
using (FileStream fs = File.Open(file, FileMode.Open))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
for (int i = 0; i < 2; i++)
{
sr.ReadLine();
}
string oline;
while ((oline = sr.ReadLine()) != null)
{
LineCount = ++LineCount;
string[] eachLine = oline.Split(';');
string date = eachLine[30].Substring(1).Substring(0, 10);
DateTime Date = DateTime.ParseExact(date, "d", CultureInfo.InvariantCulture);
int week = new GregorianCalendar(GregorianCalendarTypes.Localized).GetWeekOfYear(Date, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Saturday);
if (Convert.ToString(week) == folderName)
{
}
else
{
using (StreamWriter sw = new StreamWriter(folderPath + "/" + newFileName, true))
{
Filecount = ++Filecount;
sw.WriteLine(fileName + " " + "--" + " " + "Line number :" + " " + LineCount);
}
}
}
}
return true;
}
Your call MessageBox.Show inside ReadFile, which means every file has to write a message. This way you will get 300 messages.
Try to put your message after the WaitAll call outside the ReadFile method.
if (files.Length != 0)
{
List<Task> tasks = new List<Task>();
foreach (var file in files)
{
var task = Task.Factory.StartNew(() =>
{
bool taskResult = ReadFile(file);
return taskResult;
});
tasks.Add(task);
}
Task.WaitAll(tasks.ToArray());
// Message here
DialogResult result2 = MessageBox.Show("Read the files successfully.", "Important message", MessageBoxButtons.OK, MessageBoxIcon.Information);
}

SearchOption.AllDirectories filter

I am trying to filter out the path C:\$Recycle.bin in my file enumeration. How can I do this?
var files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories).OrderBy(p => p).ToList();
When I execute the above, I get the error below.
Additional information: Access to the path 'C:\$Recycle.Bin\S-1-5-21-1600837348-2291285090-976156579-500' is denied.
I also want to calc every file's md5. I have:
var mainDirectory = new DirectoryInfo("\\");
var files = GetDirectories(mainDirectory);
List<string> drives = new List<string>();
foreach (var file in files)
{
//Console.WriteLine(file.Name);
drives.Add(mainDirectory + file.Name);
}
MD5 md5 = MD5.Create();
foreach (string file in drives)
{
// hash path
string relativePath = file.Substring("\\".Length + 1);
byte[] pathBytes = Encoding.UTF8.GetBytes(relativePath.ToLower());
md5.TransformBlock(pathBytes, 0, pathBytes.Length, pathBytes, 0);
// hash contents
try
{
byte[] contentBytes = File.ReadAllBytes(file);
md5.TransformBlock(contentBytes, 0, contentBytes.Length, contentBytes, 0);
md5.TransformFinalBlock(contentBytes, 0, contentBytes.Length);
}
catch(UnauthorizedAccessException)
{
continue;
}
catch
{
continue;
}
Console.WriteLine(BitConverter.ToString(md5.Hash).Replace("-", "").ToLower());
}
Console.ReadKey();
The following could do it for you, but it is a quick and dirty way, because it does not handle any exceptions. I did not regard any readability and it is not fully tested.
static void Main(string[] args)
{
var mainDirectory = new DirectoryInfo("C:\\");
var files = GetFiles(mainDirectory, ".");
foreach (var file in files)
{
Console.WriteLine(file.Name);
}
Console.ReadKey();
}
static IEnumerable<DirectoryInfo> GetDirectories(DirectoryInfo parentDirectory)
{
DirectoryInfo[] childDirectories = null;
try
{
childDirectories = parentDirectory.GetDirectories();
}
catch (Exception)
{
}
yield return parentDirectory;
if (childDirectories != null)
{
foreach (var childDirectory in childDirectories)
{
var childDirectories2 = GetDirectories(childDirectory);
foreach (var childDirectory2 in childDirectories2)
{
yield return childDirectory2;
}
}
}
}
static IEnumerable<FileInfo> GetFiles(DirectoryInfo parentDirectory,
string searchPattern)
{
var directories = GetDirectories(parentDirectory);
foreach (var directory in directories)
{
FileInfo[] files = null;
try
{
files = directory.GetFiles(searchPattern);
}
catch (Exception)
{
}
if (files != null)
{
foreach (var file in files)
{
yield return file;
}
}
}
}

Making an iso file from a directory using DiscUtils

Iam trying to build an iso file from a directory with discutils. This code works fine with a couple of files but after a while i throws an exception stating that "An object with the same key already exists" at "isoBuilder.AddFile(fileOnIso,br.BaseStream);". I don't understand why this happens can someone please shed some light?
public void AddtoISO(string directory,string isoFile)
{
BinaryReader br;
long bytesRemain = 0;
long totalBytesWritten = 0;
DirectoryInfo rootDirToAdd = new DirectoryInfo(sourceName);
DirectoryInfo currentDirToAdd = new DirectoryInfo(directory);
try
{
foreach (FileInfo file in currentDirToAdd.GetFiles())
{
string fileFullPath = file.FullName;
string fileOnIso = fileFullPath.Substring(fileFullPath.IndexOf(rootDirToAdd.Name) + rootDirToAdd.Name.Length + 1);
Console.WriteLine(fileOnIso);
br = new BinaryReader(file.OpenRead());
while(totalBytesWritten < file.Length)
{
bytesRemain = file.Length - totalBytesWritten;
br.ReadBytes(blockSize);
isoBuilder.AddFile(fileOnIso,br.BaseStream);
if(bytesRemain<blockSize)
{
totalBytesWritten += bytesRemain;
totalBytesAdded += bytesRemain;
}
else
{
totalBytesWritten += blockSize;
totalBytesAdded += blockSize;
}
}
itemsAdded++;
totalBytesWritten = 0;
}
foreach (DirectoryInfo subdir in currentDirToAdd.GetDirectories())
{
string folderFullPath = subdir.FullName;
string folderOnIso = folderFullPath.Substring(folderFullPath.IndexOf(rootDirToAdd.Name) + rootDirToAdd.Name.Length + 1);
isoBuilder.AddDirectory(folderOnIso);
itemsAdded++;
AddtoISO(subdir.FullName,isoFile,ctoken);
}
isoBuilder.Build(isoFile);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
Update
An other possible implementation avoiding streams, the drawback is that it takes too much time (over 30 mins) on a 3GB iso which when built with ultraiso for example, it takes aprox 4 mins.. any ideas?
public void AddtoISO(string directory,string isoFile)
{
try
{
DirectoryInfo rootDirToAdd = new DirectoryInfo(sourceName);
DirectoryInfo currentDirToAdd = new DirectoryInfo(directory);
foreach (FileInfo file in currentDirToAdd.GetFiles())
{
string fileOnHdd = file.FullName;
string fileOnIso = fileOnHdd.Substring(fileOnHdd.IndexOf(rootDirToAdd.Name) + rootDirToAdd.Name.Length + 1);
Console.WriteLine(fileOnIso);
isoBuilder.AddFile(fileOnIso,fileOnHdd);
itemsAdded++;
}
foreach (DirectoryInfo subdir in currentDirToAdd.GetDirectories())
{
itemsAdded++;
AddtoISO(subdir.FullName,isoFile,ctoken);
}
isoBuilder.Build(isoFile);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
Update:
The exception is thrown when ever the directory structure is the following:
\boot\boot
It seems like it creates the key for boot directory and when it encounters boot.ext file it falsely thinks that it is a double addition. In other words when the files contains the name of its containing directory.
Test building dsl-4.11.rc1.iso
index.html
boot
boot\isolinux
boot\isolinux\boot.cat
boot\isolinux\boot.msg
boot\isolinux\f2
boot\isolinux\f3
boot\isolinux\german.kbd
boot\isolinux\isolinux.bin
boot\isolinux\isolinux.cfg
boot\isolinux\linux24
boot\isolinux\logo.16
boot\isolinux\minirt24.gz
KNOPPIX
KNOPPIX\KNOPPIX
Problem on KNOPPIX\KNOPPIX
Update 2
At last some progress.. the error is not in any of the given paths but im my assumption that i had to keep calling isobuilder.Addfile() until the filestream has been added to the iso entirely.
I just had to move:
isoBuilder.AddFile(fileOnIso,br.BaseStream);
Before the foreach closing bracket. This way it will no have to be added again and again in the iso.
One final problem is at the line
isoBuilder.Build(isoFile);
Where it complains about the file being closed. I tried to correct it with:
FileInfo fi = new FileInfo(isoFile);
isoBuilder.Build(fi.OpenWrite());
But it didnt help. Please someone give me the final push to solve it.
I know this is very OLD but I thought Id post if anyone else needed help with this in future.
Below is a fast and efficient function I use to build an ISO using DiscUtils.Iso9660
public string CreateIsoImage(string sourceDrive, string targetIso, string volumeName)
{
try
{
var srcFiles = Directory.GetFiles(sourceDrive, "*", SearchOption.AllDirectories);
var iso = new CDBuilder
{
UseJoliet = true,
VolumeIdentifier = volumeName
};
foreach (var file in srcFiles)
{
var fi = new FileInfo(file);
if (fi.Directory.Name == sourceDrive)
{
iso.AddFile($"{fi.Name}", fi.FullName);
continue;
}
var srcDir = fi.Directory.FullName.Replace(sourceDrive, "").TrimEnd('\\');
iso.AddDirectory(srcDir);
iso.AddFile($"{srcDir}\\{fi.Name}", fi.FullName);
}
iso.Build(targetIso);
return "Success";
}
catch (Exception ex)
{
return ex.Message;
}
}
Usage:
var res = CreateIsoImage("D:\\", "C:\\Temp\\MyIsoImage.iso", "MyVolumeName");
MessageBox.Show(res);

Categories