How to read all bytes of a stream but the last 8 - c#

I have the following code:
using (var fs = new FileStream(#"C:\dump.bin", FileMode.Create))
{
income.CopyTo(fs);
}
income is a stream that I need to save to disk, the problem is that I want to ignore the last 8 bytes and save everything before that. The income stream is read only, forward only so I cannot predict its size and I don't want to load all the stream in memory due to huge files being sent.
Any help will be appreciated.

Maybe (or rather probably) there is a cleaner way of doing it but being pragmatic at the moment the first thought which comes to my mind is this:
using (var fs = new FileStream(#"C:\dump.bin", FileMode.Create))
{
income.CopyTo(fs);
fs.SetLength(Math.Max(income.Length - 8, 0));
}
Which set's the file length after it is written.

Related

Best way to upload file using Stream

I am calling REST API which is accepting Stream to upload file from local device, so for that right now I am using following code to get Stream from a file and than closing that stream after it get's uploaded:
var stream = new FileStream(file, FileMode.Open, FileAccess.ReadWrite);
The problem with the above approach is that, until entire file gets uploaded to server user don't have any chance to delete that file because stream of that file is open, what would be the solution to resolve this issue?
If your typical file is reasonably sized (and I'm hoping you won't be uploading 2GB+ files to a REST API), you could always just read the stream into memory and before feeding it to your API, like so:
using (MemoryStream memoryStream = new MemoryStream())
{
using (FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.ReadWrite)) {
fileStream.CopyTo(memoryStream);
}
memoryStream.Position = 0; // Reset to origin.
// Now use the MemoryStream as you would a FileStream:
api.Upload(memoryStream);
}
Another alternative is to create a temp copy of the file on your hard drive and feed that to the API - but then dealing with cleanup can become a bit cumbersome. FileOptions.DeleteOnClose is your friend and may very well suffice for your purposes, but it still offers no bulletproof guarantees.

File saving as 0 KB when using HttpPostedFileBase.InputStream.CopyToAsync(FileStream) [duplicate]

I'm saving an uploaded image using this code:
using (var fileStream = File.Create(savePath))
{
stream.CopyTo(fileStream);
}
When the image is saved to its destination folder, it's empty, 0 kb. What could possible be wrong here? I've checked the stream.Length before copying and its not empty.
There is nothing wrong with your code. The fact you say "I've checked the stream.Length before copying and its not empty" makes me wonder about the stream position before copying.
If you've already consumed the source stream once then although the stream isn't zero length, its position may be at the end of the stream - so there is nothing left to copy.
If the stream is seekable (which it will be for a MemoryStream or a FileStream and many others), try putting
stream.Position = 0
just before the copy. This resets the stream position to the beginning, meaning the whole stream will be copied by your code.
I would recommend to put the following before CopyTo()
fileStream.Position = 0
Make sure to use the Flush() after this, to avoid empty file after copy.
fileStream.Flush()
This problem started for me after migrating my project from to .NET Core 1 to 2.2.
I fixed this issue by setting the Position of my filestream to zero.
using (var fileStream = new FileStream(savePath, FileMode.Create))
{
fileStream.Position = 0;
await imageFile.CopyToAsync(fileStream);
}

creating a file and allocating storage before writing to it

I have a file that gets GBs of data written to it over time (looping once it reaches the end). I would like to create the file ahead of time and preset the storage so that the required storage is never taken up by other downloads during the writing to the file. This is done using visual studio 2012 in C#.
I have tried:
if (fileSizeRequirement or fileName is changed) //if filePath or file size is changed
{
//Open or create the file, set the file to size requirement, close the filestream
fileStream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
fileStream.SetLength((long)fileSizeRequirement);
fileStream.Close();
}
1) Is this an appropriate way to "preallocate" space for a folder?
2) Will the SetLength require a seek to the beginning after setting the length or does the position in the folder stay at the beginning?
3) What is the correct way to achieve file preallocation of storage space?
Thanks ahead of time and I appreciate any suggestions.
Using SetLength is a common approach although I'd generally use a using statement here.
using(var fileStream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
fileStream.SetLength((long)fileSizeRequirement);
}
Calling fileStream.Position straight after SetLength yields 0 so you shouldn't need to seek to the beginning.

Writing to .bin binary file

I am trying to write integer numbers to binary file, but it keeps giving weird characters in the binary file. For example, I try to write 2000, but in the file i will get something strange. How do I fix it? Couldn't find the solution anywhere.
I use the following code:
//create the file
FileStream fs = new FileStream("iram.bin", FileMode.Create);
// Create the writer for data.
BinaryWriter w = new BinaryWriter(fs);
w.Write((int) 2000);
w.Close();
fs.Close();
I think the problem is that you are not reading the data back properly.
You will need to read the data back using a BinaryReader like so...
using (FileStream fs2 = new FileStream("iram.bin", FileMode.Open))
{
using(BinaryReader r = new BinaryReader(fs2))
{
var integerValue = r.ReadInt32();
}
}
Unless of course you actually want to write text to the file in which case you probably don't want a BinaryWriter to write the data out.
If you actually want to write out text data you could do so like this... (Be sure to set your encoding to what you need)
using (var tw = new StreamWriter("iram.txt", true, Encoding.ASCII))
{
tw.WriteLine(2000);
}
Edit: As Jesse mentioned you normally want to wrap disposable objects in using blocks.
The reason you're getting unexpected chars in the file is because what you're writing to the file is not meant to be interpreted as a sequence of chars in the first place
When you open it in notepad or another text editor, It will just take what's there, guess the encoding(or use a default), and show you whatever chars the data would encode if it were encoding chars. It's not intended to be human readable.
A human readable text file that has the character sequence 2000 actually has an encoding of the character 2, followed by the encoding of 0 3 times.
in Unicode it's U+0032U+0030U+0030U+0030

How to truncate a file down to certain size but keep the end section?

I have a text file that's appended to over time and periodically I want to truncate it down to a certain size, e.g. 10MB, but keeping the last 10MB rather than the first.
Is there any clever way to do this? I'm guessing I should seek to the right point, read from there into a new file, delete old file and rename new file to old name. Any better ideas or example code? Ideally I wouldn't read the whole file into memory because the file could be big.
Please no suggestions on using Log4Net etc.
If you're okay with just reading the last 10MB into memory, this should work:
using(MemoryStream ms = new MemoryStream(10 * 1024 * 1024)) {
using(FileStream s = new FileStream("yourFile.txt", FileMode.Open, FileAccess.ReadWrite)) {
s.Seek(-10 * 1024 * 1024, SeekOrigin.End);
s.CopyTo(ms);
s.SetLength(10 * 1024 * 1024);
s.Position = 0;
ms.Position = 0; // Begin from the start of the memory stream
ms.CopyTo(s);
}
}
You don't need to read the whole file before writing it, especially not if you're writing into a different file. You can work in chunks; reading a bit, writing, reading a bit more, writing again. In fact, that's how all I/O is done anyway. Especially with larger files you never really want to read them in all at once.
But what you propose is the only way of removing data from the beginning of a file. You have to rewrite it. Raymond Chen has a blog post on exactly that topic, too.
I tested the solution from "false" but it doesn't work for me, it trims the file but keeps the beginning of it, not the end.
I suspect that CopyTo copies the whole stream instead of starting for the stream position. Here's how I made it work:
int trimSize = 10 * 1024 * 1024;
using (MemoryStream ms = new MemoryStream(trimSize))
{
using (FileStream s = new FileStream(logFilename, FileMode.Open, FileAccess.ReadWrite))
{
s.Seek(-trimSize, SeekOrigin.End);
byte[] bytes = new byte[trimSize];
s.Read(bytes, 0, trimSize);
ms.Write(bytes, 0, trimSize);
ms.Position = 0;
s.SetLength(trimSize);
s.Position = 0;
ms.CopyTo(s);
}
}
You could read the file into a binary stream and use the seek method to just retrieve the last 10MB of data and load them into memory. Then you save this stream into a new file and delete the old one. The text data could be truncated though so you have to decide if this is exceptable.
Look here for an example of the Seek method:
http://www.dotnetperls.com/seek

Categories

Resources