SharpZipLib ~ How to extract specific files from a zip [duplicate] - c#

This question already has answers here:
Using SharpZipLib to unzip specific files?
(5 answers)
Closed 9 years ago.
Ok,
I have a list of files (SourceFile objects which just contain the filename only) then I want to pull those specific files out of a zip and dump them into a temp directory so I can distribute them later.
I came up with this, but I am unsure on how to proceed next..
private List<string> ExtractSelectedFiles()
{
List<SourceFile> zipFilePaths = new List<SourceFile>();
List<string> tempFilePaths = new List<string>();
if (!File.Exists(this.txtSourceSVNBuildPackage.Text)) { return tempFilePaths; };
FileStream zipFileStream = File.OpenRead(this.txtSourceSVNBuildPackage.Text);
ZipInputStream inStream = new ZipInputStream(zipFileStream);
foreach (SourceFile currentFile in _selectedSourceFiles)
{
bool getNextEntry = true;
while (getNextEntry)
{
ZipEntry entry = inStream.GetNextEntry();
getNextEntry = (entry != null);
if (getNextEntry)
{
if (fileType == ".dll")
{
if (sourcefile.Name == Path.GetFileName(entry.Name))
{
//Extract file into a temp directory somewhere
//tempFilePaths.Add("extractedfilepath")
}
}
}
}
}
return tempFilePaths;
}
FYI:
public class SourceFile
{
public string Name { get; set; } //ex. name = "Fred.dll"
}

ok.. figured I'd update you all after I got together the missing piece I needed.
//in the code somewhere above:
string tempDirectory = Environment.GetEnvironmentVariable("TEMP");
string createPath = tempDirectory + "\\" + Path.GetFileName(entry.Name);
//my missing piece..
//Extract file into a temp directory somewhere
FileStream streamWriter = File.Create(createPath);
int size = 2048;
byte[] data = new byte[2048];
while (true)
{
size = inStream.Read(data, 0, data.Length);
if (size > 0)
{
streamWriter.Write(data, 0, size);
}
else
{
break;
}
}
streamWriter.Close();

Related

Windows Service Filestream giving System.IO.IOException: The process cannot access the file "filename" because it is being used by another process

I've got a windows service that I have to modify. Current code is this:
public IRecord2 GetRecord(string name)
{
string path = Path.Combine(this.DirectoryPath, name);
if (!File.Exists(path))
return null;
byte[] contents;
lock (locker) {
using(FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize:4096, useAsync:true)) //WHERE THE PROBLEM IS OCCURRING
{
using (BinaryReader br = new BinaryReader(fs))
{
contents = br.ReadBytes((int)fs.Length);
br.Close(); //unnecessary but threw it in just to be sure
fs.Close(); //unnecessary but threw it in just to be sure
}
}
}
return new Record2()
{
Name = name,
Contents = contents
};
}
Code that calls the function:
public void Process(string pickupFileName)
{
string uniqueId = DateTime.Now.ToString("(yyyy-MM-dd_HH-mm-ss)");
string exportFileName = Path.GetFileNameWithoutExtension(pickupFileName) + "_" + uniqueId + ".csv";
string archiveFileName = Path.GetFileNameWithoutExtension(pickupFileName) + "_" + uniqueId + Path.GetExtension(pickupFileName);
string unprocessedFileName = Path.GetFileNameWithoutExtension(pickupFileName) + "_" + uniqueId + Path.GetExtension(pickupFileName);
try
{
_logger.LogInfo(String.Format("Processing lockbox file '{0}'", pickupFileName));
IRecord2 record = _pickup.GetRecord(pickupFileName);
if (record == null)
return;
_archive.AddOrUpdate(new Record2() { Name = archiveFileName, Contents = record.Contents });
string pickupFileContents = UTF8Encoding.UTF8.GetString(record.Contents);
IBai2Document document = Bai2Document.CreateFromString(pickupFileContents);
StringBuilder sb = Export(document);
_export.AddOrUpdate(new Record2() { Name = exportFileName, Contents = Encoding.ASCII.GetBytes(sb.ToString()) });
_pickup.Delete(pickupFileName);
}
catch(Exception ex)
{
throw ex;
}
}
Function that calls Process:
public void Process()
{
foreach (ConfigFolderPath configFolderPath in _configSettings.ConfigFolderPaths)
{
IRecordRepository pickup = new FileRepository(configFolderPath.PickupFolderPath);
IRecordRepository export = new FileRepository(configFolderPath.ExportFolderPath);
IRecordRepository archive = new FileRepository(configFolderPath.ArchiveFolderPath);
IRecordRepository unprocessed = new FileRepository(configFolderPath.UnprocessedFolderPath);
Converter converter = new Converter(Logger,pickup, export, archive, unprocessed);
foreach (string fileName in pickup.GetNames())
{
if (_configSettings.SupportedFileExtensions.Count > 0 && !_configSettings.SupportedFileExtensions.Any(extension => extension.ToLower() == Path.GetExtension(fileName).ToLower()))
continue;
Action action = () => converter.Process(fileName);
_queue.TryEnqueue(action, new WorkTicket() { Description = String.Format("Processing '{0}'", fileName), SequentialExecutionGroup = fileName });
}
}
}
When 1 file is sent to the service, it processes and reads the file correctly. However, if two files are sent (difference of 3 minutes), the first file will process correctly, but the second will give me "System.IO.IOException: The process cannot access the file "filename" because it is being used by another process.
Is the solution to use a mutex as per https://stackoverflow.com/a/29941548/4263285 or is there a better solution to solve this?
Edit: More context:
Service is constantly running - as soon as files are dropped into a folder, it begins the process.
get the file data (function up above)
take the data, transform it, and put it into a different file
Delete the original file from the one up above
rinse and repeat if more files
if one file is placed in the folder, it works correctly.
if two files are placed in the folder, it breaks on the second file
if service is stopped and restarted, it works again
In your code add ".Close()" here, at the end of the line :
using(FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize:4096, useAsync:true).Close())

Directory.GetFiles or DirectoryInfo.GetFiles returns empty list

I've got some strange behavior during execution in a ASP.NET application.
It doesn't matter if I set workingFolder (see code below) to System.IO.Path.GetTempPath or any other public folder (current case).
I receive a ZIP file, unpack that file (using SharpZipLib) and try to digest the files in that folder, but the System.IO GetFiles returns an empty list.
I've tried to use DirectoryInfo.GetFiles and Directory.GetFiles : both an empty list.
If I breakpoint on the Directory.Delete and look at the folder I can see the files, they're not locked and I can do anything with the files - even if I set the "run from cursor" point at the beginning of the foreach no luck - the GetFiles still return an empty list (although I can see the files in explorer).
private const string EXTENSION_LOG_FILE = ".txt";
private const string VALID_EXTENSION_MASK = "*." + EXTENSION_LOG_FILE;
var zipFolder = unpackZip(filePath, workingFolder);
foreach (var zipFileInfo in new DirectoryInfo(zipFolder).GetFiles(VALID_EXTENSION_MASK, SearchOption.TopDirectoryOnly))
{
// never get's here
value.AddRange(getLogItems(zipFileInfo.FullName));
File.Delete(zipFileInfo.FullName);
}
// this fails: folder is not empty
Directory.Delete(zipFolder);
and the unpackZip method:
private static string unpackZip(string zipFile, string workingFolder)
{
// doesn't matter what name I use, GUID or no GUID the GetFiles still returns an empty lists
var tempFolder = Path.Combine(workingFolder, Guid.NewGuid().ToString());
Directory.CreateDirectory(tempFolder);
using (var unzipStream = new ZipInputStream(File.OpenRead(zipFile)))
{
ZipEntry entry;
while ((entry = unzipStream.GetNextEntry()) != null)
{
var fileName = Path.GetFileName(entry.Name);
if (fileName == string.Empty) continue;
using (var streamWriter = File.Create(Path.Combine(tempFolder, Path.GetFileName(entry.Name))))
{
var size = 2048;
var data = new byte[2048];
while (size > 0)
{
size = unzipStream.Read(data, 0, data.Length);
streamWriter.Write(data, 0, size);
}
}
}
}
return tempFolder;
}
any suggestions?
Problem which I guessed in
private const string VALID_EXTENSION_MASK = "*." + EXTENSION_LOG_FILE;
retruns *..txt because EXTENSION_LOG_FILE = ".txt"

writing to text file does not alway work/save

i have this code that compares two text files and write the difference to a log file but for some reason the log.txt file is some times blank even when is test with some lines starting with a * these are not always written either do I have to save the text file when finished writing although this does not explain why sometimes it works any help would be great
private void compare()
{
string FilePath = #"c:\snapshot\1.txt";
string Filepath2 = #"c:\snapshot\2.txt";
int counter = 0;
string line;
string line2;
var dir = "c:\\snapshot\\log.txt";
using (FileStream fs = File.Create(dir))
{
fs.Dispose();
}
StreamWriter dest = new StreamWriter(dir);
if (File.Exists(FilePath) & File.Exists(Filepath2))
{
// Read the file and display it line by line.
using (var file = File.OpenText(FilePath))
using (var file2 = File.OpenText(Filepath2))
{
while (((line = file.ReadLine()) != null & (line2 = file2.ReadLine()) != null))
{
if (line.Contains("*"))
{
dest.WriteLine(line2);
}
else if (!line.Contains(line2))
{
dest.WriteLine(line2);
}
counter++;
}
}
}
dest.Close();
}
Everything left in the buffer should be written out once you hit the close statement on your StreamReader. If you are missing stuff then it might be that you aren't reaching that line for some reason (i.e. you crash). Also, if you are trying to look at the file while it's being written (i.e. while the program is still running), you won't necessarily see everything (since it hasn't closed).
Generally, it's better to use a using statement with the StreamReader. That should ensure that it always gets closed.
private void compare()
{
string FileName1 = #"c:\snapshot\1.txt";
string FileName2 = #"c:\snapshot\2.txt";
string FileNameOutput = #"c:\snapshot\log.txt"; //dir ???
int counter = 0; // um what's this for you aren't using it.
using (FileStream fso = new FileStream(FileNameOutput, FileMode.Create, FileAccess.Write))
{
TextWriter dest = new StreamWriter(fso);
using(FileStream fs1 = new FileStream(FileName1, FileMode.Open, FileAccess.Read))
{
using (FileStream fs2 = new FileStream(FileName2, FileMode.Open, FileAccess.Read))
{
TextReader firstFile = new StreamReader(fs1);
TextReader secondFile = new StreamReader(fs2);
while (((line1 = firstFile.ReadLine()) != null & (line2 = secondFile.ReadLine()) != null))
{
if ((line1.Contains("*") || (!line1.Contains(line2)))
{
dest.Write(line2); // Writeline would give you an extra line?
}
counter++; //
}
}
}
fso.Flush();
}
I commend the overloads of FileStream to you. Do it the way I have and the code will crash at the point you instance the stream if the user running it doesn't have all the required permissions. It's a nice way of showing what you intend, and what you don't.
PS You do know contains is case and culture sensitive?
Not sure if I'm understanding your comparing logic right, but as long as I separated comparing from whole code you can adjust it to your own needs:
public static void WriteDifferences(string sourcePath, string destinationPath, string differencesPath)
{
var sourceLines = File.ReadAllLines(sourcePath).ToList();
var destinationLines = File.ReadAllLines(destinationPath).ToList();
// make lists equal size
if (sourceLines.Count > destinationLines.Count)
{
destinationLines.AddRange(Enumerable.Range(0, sourceLines.Count - destinationLines.Count).Select(x => (string)null));
}
else
{
sourceLines.AddRange(Enumerable.Range(0, destinationLines.Count - sourceLines.Count).Select(x => (string)null));
}
var differences = sourceLines.Zip(destinationLines, (source, destination) => Compare(source, destination));
File.WriteAllLines(differencesPath, differences.Where(x => x != null));
}
private static string Compare(string source, string destination)
{
return !source.Contains(destination) || source.Contains("*") ? destination : null;
}

Matching the name and size of a file

I'm having some trouble integrating two pieces of code. The first checks the size of a file and the next one loops trough a SQL database and looks for a matching name for a file. I basically want to check if it's a new file or if the file has changed since I logged some of it's data last time.
This gets the size of each file in the directory
// Make a reference to a directory.
DirectoryInfo di = new DirectoryInfo("C:\\Users");
// Get a reference to each file in that directory.
FileInfo[] fiArr = di.GetFiles();
// Display the names and sizes of the files.
MessageBox.Show("The directory {0} contains the following files:", di.Name);
foreach (FileInfo f in fiArr)
MessageBox.Show("The size of" + f.Name + " is " + f.Length + " bytes.");
This code loops untill it finds a mach or untill all entries has been looked trough.
try
{
// LINQ query for all files containing the word '.txt'.
var files = from file in
Directory.EnumerateFiles("C:\\Users")
where file.ToLower().Contains(".txt")
select file;
foreach (var file in files)
{
//Get path to HH file
filename = System.IO.Path.GetFileName(file);
tempString = "";
//Keep looking trough database utill database empty or HH found
while (inc != numberOfSessions && (filename != tempString))
{
sessionRow = sessions.Tables["Sessions"].Rows[inc];
tempString = sessionRow.ItemArray.GetValue(1).ToString();
inc++;
}
Lets say ItemAttay.GetValue(2) returns the saved size of a file. How can i most efficiently keep the while loop going if
inc != numberOfSessions && (filename != tempString) && (sessionRow.ItemArray.GetValue(2) == f.length)
Thanks for having a look!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data;
class Program
{
static void Main(string[] args)
{
var files1 = new List<string>(Directory.GetFiles(args[0],
"*.txt",
SearchOption.AllDirectories));
List<FileData> ListFiles = new List<FileData>();
for (int i = 0; i < files1.Count; i++)
{
FileInfo file = new FileInfo(files1[i]);
FileData _tmpfile = new FileData(file.Name.ToString(), file.Length,
File.GetLastWriteTime(files1[1]).ToString("yyyy-MM-dd H:mm:ss"),
File.GetLastAccessTime(files1[1]).ToString("yyyy-MM-dd H:mm:ss"));
ListFiles.Add(_tmpfile);
}
DataSet sessions = new DataSet();
DataTable dt = sessions.Tables["Sessions"];
for (int i = 0; i < ListFiles.Count; i++)
{
//compares every file in folder to database
FileData _tmp = ListFiles[i];
for (int j = 0; j < dt.Rows.Count; j++)
{
if (_tmp.GSFileName == dt.Rows[i][0].ToString())
{
//put some code here
break;
}
if (_tmp.GSSize == long.Parse(dt.Rows[i][1].ToString()))
{
//put some code here
break;
}
}
}
}
}
public class FileData
{
string FileName = "";
public string GSFileName
{
get { return FileName; }
set { FileName = value; }
}
long Size = 0;
public long GSSize
{
get { return Size; }
set { Size = value; }
}
string DateOfModification = "";
public string GSDateOfModification
{
get { return DateOfModification; }
set { DateOfModification = value; }
}
string DateOfLastAccess = "";
public string GSDateOfLastAccess
{
get { return DateOfLastAccess; }
set { DateOfLastAccess = value; }
}
public FileData(string fn, long si, string dateofmod, string dateofacc)
{
FileName = fn;
Size = si;
DateOfModification = dateofmod;
DateOfLastAccess = dateofacc;
}
}

Error "EOF In Header" with version SharpZipLib 0.86.0.518

I use VS 2008 SP1 in Windows XP.
I have updated ICSharpCode.SharpZipLib.dll from older 0.85.4.369 to new 0.86.0.518.
I have been using it successfully for older 0.85.4.369.
I have been able to zip and unzip both files and folders without a problem - well, until now.
But now, I get error "EOF In Header" when read a ZIP file that I have generated using ICSharpCode.SharpZipLib.dll too.
My code C# is the same, no changes about it.
Fails: theEntry = z.GetNextEntry();
public static string LeerEtiquetaEmpaquetado(string zipFic)
{
ZipInputStream z = null;
DatosEmpaquetado datEmp;
try
{
z = new ZipInputStream(File.OpenRead(zipFic));
ZipEntry theEntry;
do
{
theEntry = z.GetNextEntry();
if (theEntry != null)
{
if (theEntry.Name.EndsWith("empaquetado.xml"))
{
using (MemoryStream memWrt = new MemoryStream())
{
int size = 2048;
byte[] data = new byte[2048];
do
{
size = z.Read(data, 0, data.Length);
if ((size > 0))
{
memWrt.Write(data, 0, size);
}
else
{
break;
}
} while (true);
datEmp = LeerEmpaquetado(memWrt);
return datEmp.Etiqueta;
}
break;
}
}
else
{
break;
}
} while (true);
return null;
}
catch (Exception exc)
{
System.Diagnostics.Trace.WriteLine("Excepción: " + exc.Message);
System.Diagnostics.Trace.WriteLine(exc.StackTrace);
throw;
}
finally
{
if (z != null)
{
z.Close();
z.Dispose();
}
}
}
The ICSharpCode.SharpZipLib.dll ( 0.86.0.518 ) seems unable to open the ZIPs it just created.
Very Strange thing is:
The newly-created files open just fine in WinRAR.
ZIP files created with previous versions of the DLL open just fine with the new DLL.
Code for ZIP file:
public static void EmpaquetarProyecto(string dirOutput, string nombre, string dirDestino)
{
string dirActual = Environment.CurrentDirectory;
Environment.CurrentDirectory = dirOutput;
string[] fileNames = Directory.GetFiles(".", "*.*", SearchOption.AllDirectories);
try
{
Crc32 objCrc32 = new Crc32();
ZipOutputStream strmZipOutputStream;
nombre = Path.Combine(dirDestino, nombre + ".zip");
strmZipOutputStream = new ZipOutputStream(File.Create(nombre));
strmZipOutputStream.SetLevel(6);
foreach (string aux in fileNames)
{
string strFile = aux;
if (strFile.StartsWith(".\\"))
{
strFile = strFile.Substring(2);
}
FileStream strmFile = File.OpenRead(strFile);
byte[] abyBuffer = new byte[(Convert.ToInt32(strmFile.Length))];
strmFile.Read(abyBuffer, 0, abyBuffer.Length);
ZipEntry theEntry = new ZipEntry(strFile);
FileInfo fi = new FileInfo(strFile);
theEntry.DateTime = fi.LastWriteTime;
theEntry.Size = strmFile.Length;
strmFile.Close();
objCrc32.Reset();
objCrc32.Update(abyBuffer);
theEntry.Crc = objCrc32.Value;
strmZipOutputStream.PutNextEntry(theEntry);
strmZipOutputStream.Write(abyBuffer, 0, abyBuffer.Length);
}
strmZipOutputStream.Finish();
strmZipOutputStream.Close();
}
finally
{
Environment.CurrentDirectory = dirActual;
}
}
Perhaps error is aboutCRC, I think.
Any ideas about it? any changes in my code ?
edit: If delete code about CRC , it works, but why ??

Categories

Resources