Unzip one File from Directory - c#

Everything is working fine.. I can Unzip files, from an Zip/Rar .. Archive.
The Problem is, how to Unzip a file, thats in a Directory?
To Unzip a File directly I use (SharpZipLib):
FastZip fastZip = new FastZip();
fastZip.ExtractZip(source, targetDirectory, null);
using (var fs = new FileStream(source, FileMode.Open, FileAccess.Read))
using (var zf = new ZipFile(fs))
{
var ze = zf.GetEntry("toc.out");
if (ze == null)
{
throw new ArgumentException("toc.out", "not found in Zip");
}
using (var s = zf.GetInputStream(ze))
{
// do something with ZipInputStream
}
}
}
Or with DotNetZip/ZipDotNet:
using (ZipFile zip = ZipFile.Read(source))
{
ZipEntry e = zip["toc.out"];
e.Extract();
}
Thats not working, cause hes searching the file in the root..
And I also wont do something like: DirectoryName/toc.out
How can I achieve this`? Isn't there a parameter, where I can include all subfolders - for searching or something similar? :(

You can write a LINQ expression to find the file in sub folders as shown below
DirectoryInfo dirInfo = new DirectoryInfo(#"C:\");
foreach (var file in dirs.Select(dir => dir.EnumerateFiles().Where(i => i.Name.ToLower() == "wsdl.zip").FirstOrDefault()).Where(file => file != null))
{
Console.WriteLine(file.ToString());
Console.WriteLine(file.Length);
}
The above code searches all subfolder under C drive for the file wsdl.zip and prints its name and length to the console.
Hope that helps.

You can check the last part of the Name of the entry. Even if the file is in a subfolder, the Name entry would be something like "Folder/file.ext".
An extension method to accomplish this would be like:
public static ZipEntry GetEntryExt(this ZipFile file, string fileName)
{
foreach (ZipEntry entry in file)
{
if (entry.IsFile && entry.Name.EndsWith(Path.DirectorySeparatorChar + fileName))
return entry;
}
return null;
}

Related

C# Get top level files from zip file only

I am trying to get all the file names that are located in the top level of a zip file and not anything in subdirectories.
The code I'm currently using is
using System.IO.Compression.ZipFile;
using (var zip = ZipFile.OpenRead(pathToZip))
{
foreach (var e in zip.Entries)
{
var filename = e.Name;
}
}
But this code gets all the files in the zip. Any help is much apricated.
Thanks
This code will extract only files that are not contained in a directory:
using (var zip = ZipFile.OpenRead(pathToZip))
{
foreach (var e in zip.Entries.Where(e => !e.FullName.Contains("/")))
{
{
var filename = e.Name;
Console.WriteLine(filename);
}
}
}

How to Rename Files and Folder in .rar .7z, .tar, .zip using C#

I have a compressed file .rar .7z, .tar and .zip and I want to rename physical file name available in above compressed archived using C#.
I have tried this using a sharpcompress library but I can't find such a feature for rename file or folder name within .rar .7z, .tar and .zip file.
I also have tried using the DotNetZip library but its only support.Zip see what I have tried using DotNetZip library.
private static void RenameZipEntries(string file)
{
try
{
int renameCount = 0;
using (ZipFile zip2 = ZipFile.Read(file))
{
foreach (ZipEntry e in zip2.ToList())
{
if (!e.IsDirectory)
{
if (e.FileName.EndsWith(".txt"))
{
var newname = e.FileName.Split('.')[0] + "_new." + e.FileName.Split('.')[1];
e.FileName = newname;
e.Comment = "renamed";
zip2.Save();
renameCount++;
}
}
}
zip2.Comment = String.Format("This archive has been modified. {0} files have been renamed.", renameCount);
zip2.Save();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
But actually the same as above I also want for .7z, .rar and .tar, I tried many libraries but still I didn't get any accurate solution.
Please help me.
This is a simple console application to rename files in .zip
using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
namespace Renamer
{
class Program
{
static void Main(string[] args)
{
using var archive = new ZipArchive(File.Open(#"<Your File>.zip", FileMode.Open, FileAccess.ReadWrite), ZipArchiveMode.Update);
var entries = archive.Entries.ToArray();
//foreach (ZipArchiveEntry entry in entries)
//{
// //If ZipArchiveEntry is a directory it will have its FullName property ending with "/" (e.g. "some_dir/")
// //and its Name property will be empty string ("").
// if (!string.IsNullOrEmpty(entry.Name))
// {
// var newEntry = archive.CreateEntry($"{entry.FullName.Replace(entry.Name, $"{RandomString(10, false)}{Path.GetExtension(entry.Name)}")}");
// using (var a = entry.Open())
// using (var b = newEntry.Open())
// a.CopyTo(b);
// entry.Delete();
// }
//}
Parallel.ForEach(entries, entry =>
{
//If ZipArchiveEntry is a directory it will have its FullName property ending with "/" (e.g. "some_dir/")
//and its Name property will be empty string ("").
if (!string.IsNullOrEmpty(entry.Name))
{
ZipArchiveEntry newEntry = archive.CreateEntry($"{entry.FullName.Replace(entry.Name, $"{RandomString(10, false)}{Path.GetExtension(entry.Name)}")}");
using (var a = entry.Open())
using (var b = newEntry.Open())
a.CopyTo(b);
entry.Delete();
}
});
}
//To Generate random name for the file
public static string RandomString(int size, bool lowerCase)
{
StringBuilder builder = new StringBuilder();
Random random = new Random();
char ch;
for (int i = 0; i < size; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
builder.Append(ch);
}
if (lowerCase)
return builder.ToString().ToLower();
return builder.ToString();
}
}
}
Consider 7zipsharp:
https://www.nuget.org/packages/SevenZipSharp.Net45/
7zip itself supports lots of archive formats (I believe all you mentioned) and 7zipsharp uses the real 7zip. I've used 7zipsharp for .7z files only but I bet it works for others.
Here's a sample of a test that appears to rename a file using ModifyArchive method, I suggest you go to school in it:
https://github.com/squid-box/SevenZipSharp/blob/f2bee350e997b0f4b1258dff520f36409198f006/SevenZip.Tests/SevenZipCompressorTests.cs
Here's the code simplified a bit. Note that the test compresses a 7z file for its test; that's immaterial it could be .txt, etc. Also note it finds the file by index in the dictionary passed to ModifyArchive. Consult documentation for how to get that index from a filename (maybe you have to loop and compare).
var compressor = new SevenZipCompressor( ... snip ...);
compressor.CompressFiles("tmp.7z", #"Testdata\7z_LZMA2.7z");
compressor.ModifyArchive("tmp.7z", new Dictionary<int, string> { { 0, "renamed.7z" }});
using (var extractor = new SevenZipExtractor("tmp.7z"))
{
Assert.AreEqual(1, extractor.FilesCount);
extractor.ExtractArchive(OutputDirectory);
}
Assert.IsTrue(File.Exists(Path.Combine(OutputDirectory, "renamed.7z")));
Assert.IsFalse(File.Exists(Path.Combine(OutputDirectory, "7z_LZMA2.7z")));

How to compress both files and folders with ZipFile API

I want to compress Zip to be same structure with folder.
but, ZipFile API seems unable to compress folder.
How to compress these folder structure?
The following code can't compress folder itself.
using (ZipArchive archive = ZipFile.Open(Path.Combine(m_strWorkingDirectory, "build.zip"), ZipArchiveMode.Create))
{
foreach( string path in m_listTargetPath )
{
string strPath = Path.Combine(m_strWorkingDirectory, path);
archive.CreateEntryFromFile(strPath, path);
}
}
If ZipFile.CreateFromDirectory() doesn't do what you need (I thought it would) then you can just get all the files/folders you need and add them in using an extension method:
public static class FileExtensions
{
public static IEnumerable<FileSystemInfo> AllFilesAndFolders(this DirectoryInfo dir)
{
foreach (var f in dir.GetFiles())
{
yield return f;
}
foreach (var d in dir.GetDirectories())
{
yield return d;
foreach (var o in AllFilesAndFolders(d))
{
yield return o;
}
}
}
}
And then using your same format, you should be able to do something like so (not tested):
DirectoryInfo dir = new DirectoryInfo(m_strWorkingDirectory);
using (ZipArchive archive = ZipFile.Open(Path.Combine(m_strWorkingDirectory, "build.zip"), ZipArchiveMode.Create))
{
foreach (FileInfo file in dir.AllFilesAndFolders().Where(o => o is FileInfo).Cast<FileInfo>())
{
var relPath = file.FullName.Substring(dir.FullName.Length + 1);
archive.CreateEntryFromFile(file.FullName, relPath);
}
}

Read line for each file c#

How can I read line by line for a list of files?
I have a directory with a number of files, I need to save all the files in a list and process them one by one, line by line.
So far I have done the following :
//fetching all files from directory
DirectoryInfo d = new DirectoryInfo("path");
Dictionary<int, FileInfo> DatFiles = new Dictionary<int, FileInfo>();
int filecounter = 1;
foreach (var dat in d.EnumerateFiles())
{
DatFiles.Add(filecounter, dat);
filecounter++;
}
Console.WriteLine(filecounter);
foreach (var fileName in DatFiles)
{
foreach (var line in File.ReadLines(fileName.Value.OpenText().ToString()))
{
//run some methods
}
}
When executing, I'm getting an exception, file not found. Even though the list is full of file names.
EnumerateFiles() returns a list of FileInfo objects, and File.ReadLines() takes a string path argument; you probably want to use File.ReadLines(fileName.Value.FullName) in your foreach as that gives the path to the actual file; OpenText() returns a StreamReader object.
This smaller code should do the task
var files = Directory.GetFiles("path");
foreach(var f in files)
{
using(StreamReader reader = new StreamReader(f))
{
var lines = reader.ReadToEnd().Split(new string[]{Environment.NewLine});
// Do here
}
}
When all else fails refer to the documentation
// Open the stream and read it back.
using (StreamReader sr = fi.OpenText())
{
string s = "";
while ((s = sr.ReadLine()) != null)
{
Console.WriteLine(s);
}
}

Reading a directory file by file

Is it possible to read files from a directory one file after another?
I look for something like:
while (File file = Directory.GetFile(path)) {
//
// Do something with file
//
}
[UPDATE]
I already knew about GetFiles() but I'm looking for a function that return one file at a time.
EnumerateFiles() is .Net4.x, would be nice to have, but I'm using .Net2.0. Sorry, that I didn't mention.
(Tag updated)
You can enumerate over the file names:
foreach(string fileName in Directory.EnumerateFiles(path)) {
// Do something with fileName - using `FileInfo` or `File`
}
string[] arFiles = Directory.GetFiles(#"C:\");
foreach (var sFilename in arfiles)
{
// Open file named sFilename for reading, do whatever
using (StreamReader sr = File.OpenText(sFilename ))
{
string s = "";
while ((s = sr.ReadLine()) != null)
{
Console.WriteLine(s);
}
}
}
foreach (var file in Directory.EnumerateFiles(path))
{
var currFileText = File.ReadAllText(file);
}
What about Directory.GetFiles(path) method?
foreach(String fileName in Directory.GetFiles(path))
{
FileInfo file = new FileInfo(fileName);
}
Try with this...
foreach (var filePath in Directory.GetFiles(path))
{
var text = File.ReadAllText(filePath);
// Further processing
}

Categories

Resources