Given a stream object which contains an xlsx file, I want to save it as a temporary file and delete it when not using the file anymore.
I thought of creating a class that implementing IDisposable and using it with the using code block in order to delete the temp file at the end.
Any idea of how to save the stream to a temp file and delete it on the end of use?
Thanks
You could use the TempFileCollection class:
using (var tempFiles = new TempFileCollection())
{
string file = tempFiles.AddExtension("xlsx");
// do something with the file here
}
What's nice about this is that even if an exception is thrown the temporary file is guaranteed to be removed thanks to the using block. By default this will generate the file into the temporary folder configured on the system but you could also specify a custom folder when invoking the TempFileCollection constructor.
You can get a temporary file name with Path.GetTempFileName(), create a FileStream to write to it and use Stream.CopyTo to copy all data from your input stream into the text file:
var stream = /* your stream */
var fileName = Path.GetTempFileName();
try
{
using (FileStream fs = File.OpenWrite(fileName))
{
stream.CopyTo(fs);
}
// Do whatever you want with the file here
}
finally
{
File.Delete(fileName);
}
Another approach here would be:
string fileName = "file.xslx";
int bufferSize = 4096;
var fileStream = System.IO.File.Create(fileName, bufferSize, System.IO.FileOptions.DeleteOnClose)
// now use that fileStream to save the xslx stream
This way the file will get removed after closing.
Edit:
If you don't need the stream to live too long (eg: only a single write operation or a single loop to write...), you can, as suggested, wrap this stream into a using block. With that you won't have to dispose it manually.
Code would be like:
string fileName = "file.xslx";
int bufferSize = 4096;
using(var fileStream = System.IO.File.Create(fileName, bufferSize, System.IO.FileOptions.DeleteOnClose))
{
// now use that fileStream to save the xslx stream
}
// Get a random temporary file name w/ path:
string tempFile = Path.GetTempFileName();
// Open a FileStream to write to the file:
using (Stream fileStream = File.OpenWrite(tempFile)) { ... }
// Delete the file when you're done:
File.Delete(tempFile);
EDIT:
Sorry, maybe it's just me, but I could have sworn that when you initially posted the question you didn't have all that detail about a class implementing IDisposable, etc... anyways, I'm not really sure what you're asking in your (edited?) question. But this question: Any idea of how to save the stream to temp file and delete it on the end of use? is pretty straight-forward. Any number of google results will come back for ".NET C# Stream to File" or such.
I just suggest for creating file use Path.GetTempFileName(). but others depends on your usage senario, for example if you want to create it in your temp creator class and use it just there, it's good to use using keyword.
Related
I'm wondering if there is a best practice when it comes to working with .tmp file for writing data. I like to make an .tmp that will be use in the filestream and then when I close the writer, I like to rename the file. Is there a way to rename file extension?
FileStream stream2 = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite);
StreamWriter streamWriter2 = new StreamWriter(stream2);
streamWriter2.WriteLine(textToAdd);
streamWriter2.Close();
string changed = Path.ChangeExtension(fileName, .txt);
File.Move(path, changed);
Here's how I would do this:
// Build a FileInfo object for your temp destination, this gives us
// access to a handful of useful file manipulation methods
var yourFile = new FileInfo(#"C:\temp\testfile.tmp");
// open a StreamWriter to write text to the file
using (StreamWriter sw = yourFile.CreateText())
{
// Write your text
sw.WriteLine("Test");
// There's no need to call Close() when you're using usings
}
// "Rename" the file -- this is the fastest way in C#
yourFile.MoveTo(#"C:\temp\testfile.txt");
You can use Path.GetFilenameWithoutExtension to remove the extension and then just add the one you want.
I am trying to access a file in a .7z file. I know the name of the file in the zip folder and that it exists in the .7z file. Previously I've used the ExtractArchive(templocation) which just dumps all the files into a temporary location. Now I want to be able to grab a specific file without extracting the whole .7z file.
7Zip has a class called the SevenZipExtractor that has a method ExtractFile. I would think that is what I am looking for, but I can't find any decent documentation on it.
What I need clarification on is how to go about getting the Stream parameter passed in correctly.
I am using code like this;
//this grabs the zip file and creates a FileInfo array that hold the .7z file (assume there is only one)
DirectoryInfo directoryInfo = new DirectoryInfo(ApplicationPath);
FileInfo[] zipFile = directoryInfo.GetFiles("*.7z");
//This creates the zipextractor on the zip file I just placed in the zipFile FileInfo array
using (SevenZip.SevenZipExtractor zipExtractor = new SevenZip.SevenZipExtractor(zipFile[0].FullName))
//Here I should be able to use the ExtractFile method, however I don't understand the stream parameter, and I can't find any good documentation on the method itself. What is this method looking for?
{
zipExtractor.ExtractFile("ConfigurationStore.xml", Stream stream);
}
Setup a FileStream that SevenZip can write out to:
DirectoryInfo directoryInfo = new DirectoryInfo(ApplicationPath);
FileInfo[] zipFile = directoryInfo.GetFiles("*.7z");
using (SevenZip.SevenZipExtractor zipExtractor = new SevenZip.SevenZipExtractor(zipFile[0].FullName))
{
using (FileStream fs = new FileStream("", FileMode.Create)) //replace empty string with desired destination
{
zipExtractor.ExtractFile("ConfigurationStore.xml", fs);
}
}
I've seen many issues like this that have been solved and the problem was mostly due to streams not being disposed of properly.
My issue is slightly different, here follow a code snippet
foreach (Images item in ListOfImages)
{
newPath = Path.Combine(newPath, item.ImageName + item.ImageExtension);
File.Create(newPath);
File.WriteAllBytes(newPath, item.File);
}
Where Images is a custom struct and item.File is the raw data, byte[].
My issue is that at the line where the WriteAllBytes is called, an exception is thrown. The message reads:
The process cannot access the file because it is being used by another process
Again I have no clue how am I going to somehow close the process.
Since File.Create returns the stream i would dispose it properly:
using(var stream = File.Create(newPath)){}
File.WriteAllBytes(newPath, item.File);
or you can use the stream to write to the file directly:
using (FileStream fs = File.Create(newPath))
{
fs.Write(item.File, 0, item.File.Length);
}
or, probably the easiest, use File.WriteAllBytes alone:
File.WriteAllBytes(newPath, item.File);
Creates a new file, writes the specified byte array to the file, and
then closes the file. If the target file already exists, it is
overwritten.
You state that your problem has nothing to do with disposing streams but check this MSDN article:
http://msdn.microsoft.com/en-us/library/d62kzs03.aspx
What does File.Create return? A FileStream!!!!
And, at the end of the day, why are you using File.Create if File.WriteAllBytes creates a file if this doesn't exist? ;)
Creates a new file, writes the specified byte array to the file, and
then closes the file. If the target file already exists, it is
overwritten.
Check it on MSDN too: http://msdn.microsoft.com/en-us/library/system.io.file.writeallbytes.aspx
using (FileStream fs =
new FileStream(filePath,
FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
Your log may be write locked, so try with FileShare.ReadWrite.
The create method opens the file for writing and returns a FileStream object for you to work with. Just because you are not referencing it does not mean it does not need to be returned.
foreach (Images item in ListOfImages)
{
newPath = Path.Combine(newPath, item.ImageName + item.ImageExtension);
FileStream f = File.Create(newPath);
f.Write(item.File, 0, item.File.Length);
}
The File.WriteAllBytes creates the file if necessary. You can juts use:
foreach (Images item in ListOfImages)
{
newPath = Path.Combine(newPath, item.ImageName + item.ImageExtension);
File.WriteAllBytes(newPath, item.File);
}
And are you combine path correctly?
This is the most specific way to accomplish what you are trying to do:
foreach (Images item in ListOfImages)
{
using (System.IO.FileStream output = new System.IO.FileStream(Path.Combine(newPath, item.ImageName + item.ImageExtension),
System.IO.FileMode.Create, System.IO.FileAccess.Write))
{
output.Write(item.File, 0, item.File.Length);
output.Flush();
output.Close();
}
}
You also need to fix your logic for creating the path, which I have done in my example above. You were concatenating the newPath over and over again.
Force the garbage collector to clean.
GC.Collect();
Here is my code:
public static TextWriter twLog = null;
private int fileNo = 1;
private string line = null;
TextReader tr = new StreamReader("file_no.txt");
TextWriter tw = new StreamWriter("file_no.txt");
line = tr.ReadLine();
if(line != null){
fileNo = int.Parse(line);
twLog = new StreamWriter("log_" + line + ".txt");
}else{
twLog = new StreamWriter("log_" + fileNo.toString() + ".txt");
}
System.IO.File.WriteAllText("file_no.txt",string.Empty);
tw.WriteLine((fileNo++).ToString());
tr.Close();
tw.Close();
twLog.Close();
It throws this error:
IOException: Sharing violation on path C:\Users\Water Simulation\file_no.txt
What i'm trying to do is just open a file with log_x.txt name and take the "x" from file_no.txt file.If file_no.txt file is empty make log file's name log_1.txt and write "fileNo + 1" to file_no.txt.After a new program starts the new log file name must be log_2.txt.But i'm getting this error and i couldn't understand what am i doing wrong.Thanks for help.
Well, you're trying to open the file file_no.txt for reading and for writing using separate streams. This may not work as the file will be locked by the reading stream, so the writing stream can't be created and you get the exception.
One solution would be to read the file first, close the stream and then write the file after increasing the fileNo. That way the file is only opened once at a time.
Another way would be to create a file stream for both read and write access like that:
FileStream fileStream = new FileStream(#"file_no.txt",
FileMode.OpenOrCreate,
FileAccess.ReadWrite,
FileShare.None);
The accepted answer to this question seems to have a good solution also, even though I assume you do not want to allow shared reads.
Possible alternate solution
I understand you want to create unique log files when your program starts. Another way to do so would be this:
int logFileNo = 1;
string fileName = String.Format("log_{0}.txt", logFileNo);
while (File.Exists(fileName))
{
logFileNo++;
fileName = String.Format("log_{0}.txt", logFileNo);
}
This increases the number until it finds a file number where the log file doesn't exist. Drawback: If you have log_1.txt and log_5.txt, the next file won't be log_6.txt but log_2.txt.
To overcome this, you could enumerate all the files in your directory with mask log_*.txt and find the greatest number by performing some string manipulation.
The possibilities are endless :-D
Well this may be old but the accepted answer didn't work for me. This is caused when you try to Read or Write a file you just created from a separate stream. Solving this is very simple, just dispose the filestream you used in creating it and then you can access the file freely.
if (!File.Exists(myfile))
{
var fs = new FileStream(fav, FileMode.Create);
fs.Dispose();
string text = File.ReadAllText(myfile);
}
enter image description here
var stream = new System.IO.FileStream(filePath, System.IO.FileMode.Create);
resizedBitmap.Compress(Bitmap.CompressFormat.Png, 200, stream); //problem here
stream.Close();
return resizedBitmap;
In the Compress method, I was passing the value of the quality parameter as 200, which sadly doesn't allows values outside the range 0-100.
I changed back the value of quality to 100 and the issue got fixed.
None of the proposed options helped me. But I found a solution:
In my case, the problem was with Anti-Virus, with intensive writing to a file, Anti-Virus started scanning the file and at that moment there was a problem with writing to the file.
I have been developing a web application with asp.net and I have smoe question about SharZipLib. I have a file called Template.odt (from Open Office) and this file is a compacted file (like docx) and we have some other files inside it (manifiest, xml, images etc). I need to open this file change a file called content.xml and styles.xml and save in another .odt file and give to my client. But I'm not sure if we can use temporary files, so I was thinking how to do this using MemoryStream.
Look what I got:
protected byte[ GetReport() {
Stream inputStream = File.OpenRead(Server.MapPath("~/Odt/Template.odt"));
var zipInputStream = new ZipInputStream(inputStream);
var outputStream = new MemoryStream();
var zipOutputStream = new ZipOutputStream(outputStream);
ZipEntry entry = zipInputStream.GetNextEntry();
while (entry != null) {
if (entry.Name == "content.xml")
// how change the content ?
else if (entry.Name == "styles.xml")
// how change the content ?
// how to add it or create folders in the output ?
zipOutputStream.Write( ??? );
entry = zipInputStream.GetNextEntry();
}
zipOutputStream.Flush();
return outputStream.ToArray();
}
I'm not sure if it's right but I think it's on the way.
I try to take ExtraData from ZipEntry instance but I got it null, is it normal ?
Can someone help me?
Thank you
An example of how you can update ZIP files in memory can be found here:
http://wiki.sharpdevelop.net/SharpZipLib_Updating.ashx#Updating_a_zip_file_in_memory_1
In your case, you probably have to load content.xml into a XmlDocument or XDocument to modify it - but that depends on what you are trying to change exactly.
As a sidemark: when using streams, make sure you are disposing of them. The easiest way is to wrap the operation in using statement:
using(var inputStream = File.OpenRead(Server.MapPath("~/Odt/Template.odt")))
{
// ...
}
More information on that: http://www.codeproject.com/Articles/6564/Understanding-the-using-statement-in-C