I've put together a quick test using the DotNetZip library which opens a zip file full of .bmp files and converts them to .jpg format.
Prior to this I was writing all of the files to a folder, converting them, saving out the jpg files & then removing the original bmp files, which got messy.
I'm no looking to unzip them in memory first, convert to jpg & then save.
The code works, but just isn't that quick. Can anyone give me any pointers as to what I can do to improve the code please? Also, Would threading help?
string zipToUnpack = "c:\\test\\1000.zip";
string unpackDirectory = "c:\\temp\\";
string f = string.Empty;
Bitmap bm;
MemoryStream ms;
using (ZipFile zip = ZipFile.Read(zipToUnpack))
{
foreach (ZipEntry e in zip)
{
if (e.FileName.ToLower().IndexOf(".bmp") > 0)
{
ms = new MemoryStream();
e.Extract(ms);
try
{
bm = new Bitmap(ms);
f = unpackDirectory + e.FileName.ToLower().Replace(".bmp", ".jpg");
bm.Save(f, System.Drawing.Imaging.ImageFormat.Jpeg);
}
catch (Exception ex)
{
Console.WriteLine("File: " + e.FileName + " " + ex.ToString());
}
ms.Dispose();
}
}
}
Thanks
In general, DotNetZip is single-threaded. You can open multiple archives in multiple threads, but each archive in only one thread.
If you want to enlist multiple CPUs or cores, then I can suggest calling QueueUserWorkItem for the part where you convert the data in the MemoryStream into a jpg.
The call to ZipEntry.Extract() needs to be done on the same thread, for all entries. This is because the Zipfile maintains a single FileStream for all read access, and multiple threads extracting entries will cause file pointer arithmetic errors.
So, something like this:
public class State
{
public string FileName;
public MemoryStream stream;
}
public void Run()
{
string unpackDirectory = "c:\\temp\\";
string zipToUnpack = "c:\\test\\1000.zip";
var ConvertImage = new WaitCallback( (o) => {
State s = o as State;
try
{
var bm = new Bitmap(s.stream);
var f = unpackDirectory + s.FileName.ToLower().Replace(".bmp", ".jpg");
bm.Save(f, System.Drawing.Imaging.ImageFormat.Jpeg);
}
catch (Exception ex)
{
Console.WriteLine("File: " + s.FileName + " " + ex.ToString());
}
});
using (ZipFile zip = ZipFile.Read(zipToUnpack))
{
foreach (ZipEntry e in zip)
{
if (e.FileName.ToLower().IndexOf(".bmp") > 0)
{
var ms = new MemoryStream();
e.Extract(ms);
ThreadPool.QueueUserWorkItem ( ConvertImage,
new State {
FileName = e.FileName, stream = ms }
});
}
}
}
}
Related
I'm doing a c# wcf service in which I receive a bunch of images and the service merge them in a multiimage Tiff file. At the end of the service I want to delete the original files but I'm receiving an error that some other process is locking the file.
This is the code that receives the images (as a byte[] list) and write them to disk
public static List<string> SaveByteImagesToFile(List<byte[]> bytesToCopyIntoFiles, string imageReferenceType, string imageReferenceValue)
{
_applicationLogger.Debug(MethodBase.GetCurrentMethod().DeclaringType.Name, MethodBase.GetCurrentMethod().Name);
string imageFinalPath = string.Empty;
string joinImagesFilePath = string.Empty;
List<string> imagesFilePath = new List<string>();
int count = 1;
try
{
if (bytesToCopyIntoFiles.Count == 0)
{
throw new ArgumentNullException("bytesToCopyIntoFiles");
}
else
{
joinImagesFilePath = SettingsManager.GetServiceSetting(AppSettingsKeys.CopyImagesToFilePath, "NO_VALID_FILEPATH");
if (joinImagesFilePath.IsValidFilePath(out string errorMessage, true, true))
{
foreach (byte[] image in bytesToCopyIntoFiles)
{
var imageFileName = imageReferenceType + "_" + imageReferenceValue + "_" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + count.ToString();
imageFinalPath = joinImagesFilePath + Path.DirectorySeparatorChar + imageFileName + ".tiff";
using (FileStream stream = new FileStream(imageFinalPath, FileMode.Create, FileAccess.ReadWrite))
{
stream.Write(image, 0, image.Length);
stream.Flush();
}
imagesFilePath.Add(imageFinalPath);
count++;
}
}
else
{
exceptionMessageType = MainRepository.GetExceptionMessage("E171");
throw new IOException(exceptionMessageType.ExceptionMessage + " " + errorMessage);
}
}
return imagesFilePath;
}
catch
{
throw;
}
}
How or what can I use to prevent the service or any process to lock the file. As you can see I'm using the using scope for filestream without any luck.
Any ideas? Thanks
Resolved! By organizing the files in a certain order, when creating the multipage tiff, by the time the logic ends the worker already unlock the resources and I'm able now to delete them without any issue.
i would like to zip the multiple files in the folder , however my code below was working but its not zip the files and im not sure what goings on as it getting null value . Kindly advise
private static string filepath = string.IsNullOrEmpty(ConfigurationManager.AppSettings["AConvert"])
? "" : ConfigurationManager.AppSettings["AConvert"];
static void Main(string[] args)
{
string zipFileName;
string fileExt;
try
{
fileExt = Path.GetExtension(filepath);
zipFileName = filepath.Replace(fileExt + DateTime.Now.ToString("MMyy"), ".zip");
using (ZipOutputStream s = new ZipOutputStream(File.Create(zipFileName)))
{
s.Password = "ABC123";
s.SetLevel(4); // 0 - store only to 9 - means best compression
byte[] buffer = new byte[4096];
ZipEntry entry = new ZipEntry(Path.GetFileName(filepath));
entry.DateTime = DateTime.Now;
s.PutNextEntry(entry);
using (FileStream fs = File.OpenRead(filepath))
{
int sourceBytes;
do
{
sourceBytes = fs.Read(buffer, 0, buffer.Length);
s.Write(buffer, 0, sourceBytes);
} while (sourceBytes > 0);
}
s.Finish();
s.Close();
}
}
catch (Exception ex)
{
Console.WriteLine("Exception during processing {0}", ex);
}
}
Not sure what your input is here, but I suspect you might want to use Path.GetFileName() instead of Path.GetExtension.
You are currently just getting an empty string, since "D:\Report" does not have an extention.
Furthermore, I believe you would have to do this for each file in the directory, and not just for the directory as a whole, if you want to zip the files that way.
Personally I would recommend you take a look at the dotnetzip library instead. It has some brilliantly simple ways to create zip-archives and add files to it. In your case, basically something like:
var yourListOfFilePaths = Directory.GetFiles(pathToYourDir);
using (ZipFile zip = new ZipFile())
{
foreach(string filePath in yourListOfFilePaths)
{
zip.AddFile(filePath);
}
zip.Save(pathToTargetDir + "\\MyZipFile.zip");
}
PS: You can find more C# examples for DotNetZip here.
ok guys , its working right now . here the code that i amend from the Kjartan. Thanks
private static string filepath = string.IsNullOrEmpty(ConfigurationManager.AppSettings["AConvert"]) ? "" : ConfigurationManager.AppSettings["AConvert"];
private static string ZipPath = string.IsNullOrEmpty(ConfigurationManager.AppSettings["PathZip"]) ? "" : ConfigurationManager.AppSettings["PathZip"];
static void Main(string[] args)
{
var yourListOfFilePaths = Directory.GetFiles(filepath);
using (ZipFile zip = new ZipFile())
{
foreach (string filePath in yourListOfFilePaths)
{
zip.AddFile(filePath);
}
zip.Save(ZipPath + "\\Batch" + DateTime.Now.ToString("ddmmyy") + ".zip");
}
I am facing a issue in my code. PFA my code below
// Extract Zip File
public static void Extract(string zipFileName, string destinationPath)
{
ZipFile zipfile = new ZipFile(zipFileName);
List<ZipEntry> zipFiles= GetZipFiles(zipfile);
foreach (ZipEntry zipFile in zipFiles)
{
if (!zipFile.isDirectory())
{
java.io.InputStream s=zipfile.getInputStream(zipFile);
//InputStream s = zipfile.getInputStream(zipFile);
try
{
Directory.CreateDirectory(destinationPath + "\\" + Path.GetDirectoryName(zipFile.getName()));
// Directory.CreateDirectory(destinationPath + "\ + Path.GetDirectoryName(zipFile.getName()));
//Directory.CreateDirectory(Path.GetDirectoryName(zipFile.getName()));
java.io.FileOutputStream dest = new java.io.FileOutputStream(Path.Combine(destinationPath + "\\" + Path.GetDirectoryName(zipFile.getName()),
//java.io.FileOutputStream dest = new java.io.FileOutputStream(Path.Combine(Path.GetDirectoryName(zipFile.getName()),
Path.GetFileName(zipFile.getName())));
try
{
int len = 0;
byte[] buffer = new byte[7168];
while ((len = s.read(buffer)) >= 0)
{
dest.write(buffer, 0, len);
}
}
finally
{
dest.close();
}
}
finally
{
s.close();
}
}
}
}
Issue is : In this class can any one tell me formatof "string zipFileName, string destinationPath " means : which pathformate be use in zipFileName and designationPath.
This code is used for Unzip file using J# in c# please help me as soon as possible
: here zipFilename is path file to be ziped and destinationPath is path where file to be unzipped.
If I understand your question correctly, and you're working on Windows, then you would probably use a format like:
Extract(#"c:\myfolder\mysubfolder\myfile.zip", #"c:\mydestinationfolder\mysubfolder");
Give it a try and leave a comment to let me know if it works, or whatever else you've tried previously.
Are you using any compression libraries . For example the ZipFile - Is this any third party library ?
You can check compression libraries for C# that are available incase you plan to implement it.
I am using the library ICSharpCode.SharpZipLib.Zip;
My code is follows:
The path is root. \\ALAWP\\THIS\\ACORD\\
I'm zipping them to the ZIPDirectory
However when it's done the file is not named acord_combined.txt, instead it's called ACORD\acord_combined.txt
What am I doing wrong?
public void CleanRoot()
{
DirectoryInfo RootDi = new DirectoryInfo(FilePrep.RootDirectory);
string ZipDirectory = FilePrep.RootDirectory + "\\processed\\AceKey"+ DateTime.Now.ToString("yyyyMMdd_H;mm;ss") +".zip";
ZipOutputStream NewZipOutput = new ZipOutputStream(File.Create(ZipDirectory));
foreach (FileInfo fi in RootDi.GetFiles("acord*.*"))
{
Compress(ref NewZipOutput, fi);
//MoveFile(fi.FullName,ZipDirectory);
}
NewZipOutput.Finish();
NewZipOutput.Close();
}
public void Compress(ref ZipOutputStream ZipFolder, FileInfo fi)
{
try
{
FileStream fsFileToBeZipped = fi.OpenRead();
ZipEntry entry = new ZipEntry(fi.FullName);
ZipFolder.PutNextEntry(entry);
int size = 2048;
byte[] buffer = new byte[size];
while (true)
{
size = fsFileToBeZipped.Read(buffer, 0, buffer.Length);
if (size > 0)
ZipFolder.Write(buffer, 0, size);
else
break;
} //end while ( true )
fsFileToBeZipped.Close();
//prepare and delete file
fi.Attributes = FileAttributes.Normal;
//fi.Delete();
} //end try
catch (Exception e)
{
Console.WriteLine("Error zipping File. Error - " + e.Message);
} //end catch
}
Your problem is right here
new ZipEntry(fi.FullName);
The argument to zipEntry is the path in the zip file, not the full path the compressed data comes from. Usually zip libraries, such as 7zip and SharpZip, expose a way to create an "entry path" but the actual data written to the zip is from the full path.
Probably what you want is
new ZipEntry(Path.GetFileName(fi.fullName))
I am working on a project that downloads some images and put them in a arrarList to be processed later. The following portion of code is where the problem is. It works with first download, but somehow the file images were saving to is locked up after the first download. I can't seems to find a way to unlock it. File.Delete("BufferImg"); is giving error saying the file is been used by another process when "BufferImg" was not used anywhere else of the program. What am I doing wrong?
int attempcnt=0;
if (ok)
{
System.Net.WebClient myWebClient = new System.Net.WebClient();
try
{
myWebClient.DownloadFile(pth, "BufferImg");
lock (IMRequest) { IMRequest.RemoveAt(0); }
attempcnt = 0;
}
catch // will attempcnt 3 time before it remove the request from the queue
{
attempcnt++;
myWebClient.Dispose();
myWebClient = null;
if(attempcnt >2)
{
lock (IMRequest) { IMRequest.RemoveAt(0); }
attempcnt = 0;
}
goto endofWhile;
}
myWebClient.Dispose();
myWebClient = null;
using (Image img = Image.FromFile("BufferImg"))
{
lock (IMBuffer)
{
IMBuffer.Add(img.Clone());
MessageBox.Show("worker filled: " + IMBuffer.Count.ToString() + ": " + pth);
}
img.Dispose();
}
}
endofWhile:
File.Delete("BufferImg");
continue;
}
The following line is why the image is not being released:
IMBuffer.Add(img.Clone());
When you clone something loaded through a resource (file), the file is still attached to the cloned object. You will have to use a FileStream, like so:
FileStream fs = new FileStream("BufferImg", FileMode.Open, FileAccess.Read);
using (Image img = Image.FromStream(fs))
{
lock (IMBuffer)
{
IMBuffer.Add(img);
MessageBox.Show("worker filled: " + IMBuffer.Count.ToString() + ": " + pth);
}
}
fs.Close();
This should release the file after you've loaded it in the buffer.