EndOfStreamException: Failed to Read past end of stream (Unity 3d) - c#

i'm trying to decompress a file in memory using GZipStream, copy the decompressed data to a MemoryStream, and then read the MemoryStream using BinaryReader (from Unity 3d). However, i get these errors when i try to run it:
EndOfStreamException: Failed to read past end of stream.
System.IO.BinaryReader.FillBuffer (Int32 numBytes) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.IO/BinaryReader.cs:119)
System.IO.BinaryReader.ReadInt32 () (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.IO/BinaryReader.cs:432)
LoadNii.LoadNifti (System.String fullPath, Boolean loadFromResources) (at Assets/scripts/LoadNii.cs:240)
opengl_main.PrepareNewAnatomy (System.String fullPath, Boolean loadFromResources) (at Assets/scripts/opengl_main.cs:193)
opengl_main.LoadFileUsingPath () (at Assets/scripts/opengl_main.cs:656)
UnityEngine.Component:SendMessage(String, Object)
SimpleFileBrowser.Scripts.GracesGames.FileBrowser:SendCallbackMessage(String) (at Assets/Resources/SimpleFileBrowser/Scripts/GracesGames/FileBrowser.cs:274)
SimpleFileBrowser.Scripts.GracesGames.FileBrowser:SelectFile() (at Assets/Resources/SimpleFileBrowser/Scripts/GracesGames/FileBrowser.cs:267)
UnityEngine.EventSystems.EventSystem:Update()
anyone know what the problem is? is there another way to unzip a file in memory, and transfer it to a binaryReader? thanks
code:
Stream stream = null;
if (loadFromResources == true)
{
TextAsset textAsset = Resources.Load(fullPath) as TextAsset;
Debug.Log(textAsset);
stream = new MemoryStream(textAsset.bytes);
}
else
{
FileInfo fi1 = new FileInfo(fullPath);
if (fi1.Extension.Equals(".gz"))
{
stream = new MemoryStream();
byte[] buffer = new byte[4096];
using (Stream inGzipStream = new GZipStream(File.Open(fullPath,FileMode.Open), CompressionMode.Decompress))
{
int bytesRead;
while ((bytesRead = inGzipStream.Read(buffer, 0, buffer.Length)) > 0)
{
stream.Write(buffer, 0, bytesRead);
}
}
}
else
stream = File.Open(fullPath, FileMode.Open);
}
using (BinaryReader reader = new BinaryReader(stream))
{
//header headerKey substruct:
headerKey.sizeof_hdr = reader.ReadInt32(); //ERROR
}

Each time you write to a stream, its Position is increased.
Just set stream.Position = 0 after writing to it, so that you'll start reading from the first byte again afterwards.

This is just a function that deserializes and get your result back. Thank you #C.Evenhuis.
/// <summary>
///Get data from a binary file.
/// </summary>
/// <param name="filename"></param>
/// <param name="path"></param>
/// <returns>Null if no object is found </returns>
public static T GetData<T>(string filename, string path)
{
//Path is empty.
if (string.IsNullOrEmpty(path)) throw new NullReferenceException("Path can not be null or empty");
//file is empty.
if (string.IsNullOrEmpty(filename)) throw new NullReferenceException("File name can not be null or empty.");
//Storage path
var storagePath = Path.Combine(path, filename);
//check file not exist
if (!File.Exists(storagePath))
throw new NullReferenceException("No file with the name " + filename + "at location" + storagePath);
else
try
{
//create new binary formatter .
BinaryFormatter binaryFormatter = new BinaryFormatter();
//Read the file.
using (FileStream fileStream = File.Open(storagePath, FileMode.Open))
{
//result .
var result = binaryFormatter.Deserialize(fileStream);
//Set file stream to zero .
//to avoid Exception: FailedSystem.IO.EndOfStreamException:
//Failed to read past end of stream.
fileStream.Position = 0;
//Check if casting is possible and raise error accordin to that .
return (T)Convert.ChangeType(binaryFormatter.Deserialize(fileStream), typeof(T));
}
}
catch (Exception ex)
{
throw new Exception("Failed" + ex);
}
}

Related

Replicate Wave file using Naudio - Copy/Append Latest Available bytes

I have an Active wave recording wave-file.wav happening to the Source folder.
I need to replicate this file to Destination folder with a new name wave-file-copy.wav.
The recording and replication should happen in parallel.
I have implemented a scheduled job, which will run in every 10 minutes and copy the source file to destination.
private static void CopyWaveFile(string destinationFile, string sourceFile){
using (var fs = File.Open(sourceFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){
using (var reader = new WaveFileReader(fs)){
using (var writer = new WaveFileWriter(destinationFile, reader.WaveFormat)){
reader.Position = 0;
var endPos = (int)reader.Length;
var buffer = new byte[1024];
while (reader.Position < endPos){
var bytesRequired = (int)(endPos - reader.Position);
if (bytesRequired <= 0) continue;
var bytesToRead = Math.Min(bytesRequired, buffer.Length);
var bytesRead = reader.Read(buffer, 0, bytesToRead);
if (bytesRead > 0){
writer.Write(buffer, 0, bytesRead);
}
}
}
}
}
}
The copy operation is working fine, even though the source file is being updated continuously.
Time taken for the copy operation is increasing in linear time, because i am copying the entire file every time.
I am trying to implement a new function ConcatenateWavFiles(), which should update the content of destination file, with the latest available bytes of source recording.
I have tried few sample codes - the approach i am using is :
Read destination file meta info, and get the length.
Set the length of destination file as reader.Position of source file waveReader
Read the source file till end, starting from position.
public static void ConcatenateWavFiles(string destinationFile, string sourceFile){
WaveFileWriter waveFileWriter = null;
var sourceReadOffset = GetWaveFileSize(destinationFile);
try{
using (var fs = File.Open(sourceFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (var reader = new WaveFileReader(fs))
{
waveFileWriter = new WaveFileWriter(destinationFile, reader.WaveFormat);
if (!reader.WaveFormat.Equals(waveFileWriter.WaveFormat)){
throw new InvalidOperationException(
"Can't append WAV Files that don't share the same format");
}
var startPos = sourceReadOffset - sourceReadOffset % reader.WaveFormat.BlockAlign;
var endPos = (int) reader.Length;
reader.Position = startPos;
var bytesRequired = (int)(endPos - reader.Position);
var buffer = new byte[bytesRequired];
if (bytesRequired > 0)
{
var bytesToRead = Math.Min(bytesRequired, buffer.Length);
var bytesRead = reader.Read(buffer, 0, bytesToRead);
if (bytesRead > 0)
{
waveFileWriter.Write(buffer, startPos, bytesRead);
}
}
}
}
}
finally{
if (waveFileWriter != null){
waveFileWriter.Dispose();
}
}
}
I was able to get the new content.
Is it possible to append the latest content to existing destination file?
If possible what am I doing wrong in the code?
My code throws the following exception - Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.
I couldn't find a solution to wave audio file replication with NAudio Library.
But I have implemented a solution using C# MemoryStreams and FileStreams.
Copy the Source file to destination, if destination file doesn't exist.
Append all the latest bytes (recorded after the last operation) to the destination file.
Modify the Wave File Header to to reflect the last appended bytes. (Else the duration of the file will not be updated, only the file size will increase.
Repeat this append operation in regular intervals.
public void ReplicateFile(string destinationFile, string sourceFile){
if (!Directory.Exists(GetRoutePathFromFile(sourceFile)))
return;
if (!File.Exists(sourceFile))
return;
if (Directory.Exists(GetRoutePathFromFile(destinationFile))){
if (File.Exists(destinationFile)){
UpdateLatestWaveFileContent(destinationFile, sourceFile);
}else{
CopyWaveFile(destinationFile, sourceFile);
}
}else{
Directory.CreateDirectory(GetRoutePathFromFile(destinationFile));
CopyWaveFile(destinationFile, sourceFile);
}
}
private static string GetRoutePathFromFile(string file){
var rootPath = Directory.GetParent(file);
return rootPath.FullName;
}
private static void CopyWaveFile(string destination, string source){
var sourceMemoryStream = new MemoryStream();
using (var fs = File.Open(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){
fs.CopyTo(sourceMemoryStream);
}
using (var fs = new FileStream(destination, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.ReadWrite)){
sourceMemoryStream.WriteTo(fs);
}
}
private static void UpdateLatestWaveFileContent(string destinationFile, string sourceFile){
var sourceMemoryStream = new MemoryStream();
long offset = 0;
using (var fs = File.Open(destinationFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){
offset = fs.Length;
}
using (var fs = File.Open(sourceFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){
fs.CopyTo(sourceMemoryStream);
}
var length = sourceMemoryStream.Length - offset;
var buffer = sourceMemoryStream.GetBuffer();
using (var fs = new FileStream(destinationFile, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)){
fs.Write(buffer, (int)offset, (int)length);
}
var bytes = new byte[45];
for (var i = 0; i < 45; i++){
bytes[i] = buffer[i];
}
ModifyHeaderDataLength(destinationFile, 0, bytes);
}
private static void ModifyHeaderDataLength(string filename, int position, byte[] data){
using (Stream stream = File.Open(filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite))
{
stream.Position = position;
stream.Write(data, 0, data.Length);
}
}
Try Reading the Source File one or two Wav blocks prior to the actual end of the source file.
The case could be that the code is judging the end of the source file too close for comfort.

Copy and update content of actively recording Wav file to a new file

I have an active audio recording happening in WAV format with NAudio Library.
private void RecordStart() {
try {
_sourceStream = new WaveIn {
DeviceNumber = _recordingInstance.InputDeviceIndex,
WaveFormat =
new WaveFormat(
44100,
WaveIn.GetCapabilities(_recordingInstance.InputDeviceIndex).Channels)
};
_sourceStream.DataAvailable += SourceStreamDataAvailable;
if (!Directory.Exists(_recordingInstance.AudioFilePath)) {
Directory.CreateDirectory(_recordingInstance.AudioFilePath);
}
WaveFileWriter _waveWriter = new WaveFileWriter(
_recordingInstance.AudioFilePath + _recordingInstance.AudioFileName,
_sourceStream.WaveFormat);
_sourceStream.StartRecording();
}
catch (Exception exception) {
Log.Error("Recording failes", exception);
}
}
private void SourceStreamDataAvailable(object sender, WaveInEventArgs e) {
if (_waveWriter == null) return;
_waveWriter.Write(e.Buffer, 0, e.BytesRecorded);
_waveWriter.Flush();
}
I want to copy the latest available content to another location. The copied file should be in WAV format, and should be able to play the available duration. Update the destination file, whenever more content is available.
I have Tried the following sample code (using NAudio) with a static WAV file, but the solution is not working.
The resulting WAV file created is corrupted - not in the correct format.
using (WaveFileReader reader = new WaveFileReader(remoteWavFile))
{
byte[] buffer = new byte[reader.Length];
int read = reader.Read(buffer, 0, buffer.Length);
}
When the recording is in progress, the code throws an exception "File is in use by another application".
I have solved the problem with help of NAudio Library itself.
When we only use the WaveFileReader class of NAudio. It will throw the exception - "file is in use by another application".
So I had to create a file stream, which opens the source file - live recording file, with File.Open(inPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) then pass this stream as an input of WaveFileReader.
Then create a WaveFileWritter class of NAudio, with the same WavFormat of the reader.
copied below is the code, i have used.
public static void CopyWavFile(string inPath, string outPath){
using (var fs = File.Open(inPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){
using (var reader = new WaveFileReader(fs)){
using (var writer = new WaveFileWriter(outPath, reader.WaveFormat)){
reader.Position = 0;
var endPos = (int)reader.Length;
var buffer = new byte[1024];
while (reader.Position < endPos){
var bytesRequired = (int)(endPos - reader.Position);
if (bytesRequired <= 0) continue;
var bytesToRead = Math.Min(bytesRequired, buffer.Length);
var bytesRead = reader.Read(buffer, 0, bytesToRead);
if (bytesRead > 0){
writer.Write(buffer, 0, bytesRead);
}
}
}
}
}
}

GZipStream complains magic number in header is not correct

I'm attempting to use National Weather Service (U.S.) data, but something has changed recently and the GZip file no longer opens.
.NET 4.5 complains that...
Message=The magic number in GZip header is not correct. Make sure you are passing in a GZip stream.
Source=System
StackTrace:
at System.IO.Compression.GZipDecoder.ReadHeader(InputBuffer input)
at System.IO.Compression.Inflater.Decode()
at System.IO.Compression.Inflater.Inflate(Byte[] bytes, Int32 offset, Int32 length)
at System.IO.Compression.DeflateStream.Read(Byte[] array, Int32 offset, Int32 count)
I don't understand what has changed, but this is becoming a real show-stopper. Can anyone with GZip format experience tell me what has changed to make this stop working?
A file that works:
http://www.srh.noaa.gov/ridge2/Precip/qpehourlyshape/2015/201504/20150404/nws_precip_2015040420.tar.gz
A file that doesn't work:
http://www.srh.noaa.gov/ridge2/Precip/qpehourlyshape/2015/201505/20150505/nws_precip_2015050505.tar.gz
Update with sample code
const string url = "http://www.srh.noaa.gov/ridge2/Precip/qpehourlyshape/2015/201505/20150505/nws_precip_2015050505.tar.gz";
string appPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string downloadPath = Path.Combine(appPath, Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "nws_precip_2015050505.tar.gz");
using (var wc = new WebClient())
{
wc.DownloadFile(url, downloadPath);
}
string extractDirPath = Path.Combine(appPath, "Extracted");
if (!Directory.Exists(extractDirPath))
{
Directory.CreateDirectory(extractDirPath);
}
string extractFilePath = Path.Combine(extractDirPath, "nws_precip_2015050505.tar");
using (var fsIn = new FileStream(downloadPath, FileMode.Open, FileAccess.Read))
using (var fsOut = new FileStream(extractFilePath, FileMode.Create, FileAccess.Write))
using (var gz = new GZipStream(fsIn, CompressionMode.Decompress, true))
{
gz.CopyTo(fsOut);
}
It appears that this service SOMETIMES returns tar format files disguised as .tar.gz. This is very confusing, but if you check that the first two bytes are 0x1F and 0x8B, you can detect if the file is a GZip by checking its magic numbers manually.
using (FileStream fs = new FileStream(downloadPath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[2];
fs.Read(buffer, 0, buffer.Length);
if (buffer[0] == 0x1F
&& buffer[1] == 0x8B)
{
// It's probably a GZip file
}
else
{
// It's probably not a GZip file
}
}
[Resolved] GZipStream complains magic number in header is not correct
//Exception magic number tar.gz file
Migcal error cause
File is not compress into tar.gz properly
File size is too big , above 1+GB
Solution over it
use .net framework 4.5.1 to over the this exception //OR//
manupulate the exsiting solution without change .net framework.
Please follow the step for implementation.
Remane abc.tar.gz as abc (remove extension).
pass this file and directly name to compress function
*public static void Compress(DirectoryInfo directorySelected, string directoryPath)
{
foreach (FileInfo fileToCompress in directorySelected.GetFiles())
{
using (FileStream originalFileStream = fileToCompress.OpenRead())
{
if ((File.GetAttributes(fileToCompress.FullName) &
FileAttributes.Hidden) != FileAttributes.Hidden & fileToCompress.Extension != ".tar.gz")
{
using (FileStream compressedFileStream = File.Create(fileToCompress.FullName + ".tar.gz"))
{
using (System.IO.Compression.GZipStream compressionStream = new System.IO.Compression.GZipStream(compressedFileStream,
System.IO.Compression.CompressionMode.Compress))
{
originalFileStream.CopyTo(compressionStream);
}
}
FileInfo info = new FileInfo(directoryPath + "\\" + fileToCompress.Name + ".tar.gz");
}
}
}
}
3. implement this code in following exception handler try catch block
try
{
TarGzFilePath=#"c:\temp\abc.tar.gz";
FileStream streams = File.OpenRead(TarGzFilePath);
string FileName=string.Empty;
GZipInputStream tarGz = new GZipInputStream(streams);
TarInputStream tar = new TarInputStream(tarGz);
// exception will occured in below lines should apply try catch
TarEntry ze;
try
{
ze = tar.GetNextEntry();// exception occured here "magical number"
}
catch (Exception extra)
{
tar.Close();
tarGz.Close();
streams.Close();
//please close all above , other wise it will come with exception "tihs process use by another process"
//rename your file *for better accuracy you can copy file to other location
File.Move(#"c:\temp\abc.tar.gz", #"c:\temp\abc"); // rename file
DirectoryInfo directorySelected = new DirectoryInfo(Path.GetDirectoryName(#"c:\temp\abc"));
Compress(directorySelected, directoryPath); // directorySelected=c:\temp\abc , directoryPath=c:\temp\abc.tar.gz // process in step 2 function
streams = File.OpenRead(TarGzFilePath);
tarGz = new GZipInputStream(streams);
tar = new TarInputStream(tarGz);
ze = tar.GetNextEntry();
}
// do anything with extraction with your code
}
catch (exception ex)
{
tar.Close();
tarGz.Close();
streams.Close();
}

Datacontractserializer doesn't overwrite all data

I've noticed that if I persist an object back into file using a Datacontractserializer, if the length of the new xml is shorter than the xml originally present in the file the remnants of the original xml outwith the length of the new xml will remain in the file and will break the xml.
Does anyone have a good solution to fix this?
Here's the code I am using to persist the object:
/// <summary>
/// Flushes the current instance of the given type to the datastore.
/// </summary>
private void Flush()
{
try
{
string directory = Path.GetDirectoryName(this.fileName);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
FileStream stream = null;
try
{
stream = new FileStream(this.fileName, FileMode.OpenOrCreate);
for (int i = 0; i < 3; i++)
{
try
{
using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream, new System.Text.UTF8Encoding(false)))
{
stream = null;
// The serializer is initialized upstream.
this.serializer.WriteObject(writer, this.objectValue);
}
break;
}
catch (IOException)
{
Thread.Sleep(200);
}
}
}
finally
{
if (stream != null)
{
stream.Dispose();
}
}
}
catch
{
// TODO: Localize this
throw;
//throw new IOException(String.Format(CultureInfo.CurrentCulture, "Unable to save persistable object to file {0}", this.fileName));
}
}
It's because of how you are opening your stream with:
stream = new FileStream(this.fileName, FileMode.OpenOrCreate);
Try using:
stream = new FileStream(this.fileName, FileMode.Create);
See FileMode documentation.
I believe this is due to using FileMode.OpenOrCreate. If the file already exits, I think the file is being opened and parts of the data are being overwritten from the start byte. If you change to using FileMode.Create it forces any existing files to be overwritten.

StreamReader ReadToEnd() returns empty string on first attempt

I know this question has been asked before on Stackoverflow, but could not find an explanation.
When I try to read a string from a compressed byte array I get an empty string on the first attempt, on the second I succed and get the string.
Code example:
public static string Decompress(byte[] gzBuffer)
{
if (gzBuffer == null)
return null;
using (var ms = new MemoryStream(gzBuffer))
{
using (var decompress = new GZipStream(ms, CompressionMode.Decompress))
{
using (var sr = new StreamReader(decompress, Encoding.UTF8))
{
string ret = sr.ReadToEnd();
// this is the extra check that is needed !?
if (ret == "")
ret = sr.ReadToEnd();
return ret;
}
}
}
}
All suggestions are appreciated.
- Victor Cassel
I found the bug. It was as Michael suggested in the compression routine. I missed to call Close() on the GZipStream.
public static byte[] Compress(string text)
{
if (string.IsNullOrEmpty(text))
return null;
byte[] raw = Encoding.UTF8.GetBytes(text);
using (var ms = new MemoryStream())
{
using (var compress = new GZipStream (ms, CompressionMode.Compress))
{
compress.Write(raw, 0, raw.Length);
compress.Close();
return ms.ToArray();
}
}
}
What happened was that the data seemed to get saved in a bad state that required two calls to ReadToEnd() in the decompression routine later on to extract the same data. Very odd!
try adding ms.Position = 0 before string ret = sr.ReadToEnd();
Where is gzBuffer coming from? Did you also write the code that is producing the compressed data?
Perhaps the buffer data you have is invalid or somehow incomplete, or perhaps it consists of multiple deflate streams concatenated together.
I hope this helps.
For ByteArray:
static byte[] CompressToByte(string data)
{
MemoryStream outstream = new MemoryStream();
GZipStream compressionStream =
new GZipStream(outstream, CompressionMode.Compress, true);
StreamWriter writer = new StreamWriter(compressionStream);
writer.Write(data);
writer.Close();
return StreamToByte(outstream);
}
static string Decompress(byte[] data)
{
MemoryStream instream = new MemoryStream(data);
GZipStream compressionStream =
new GZipStream(instream, CompressionMode.Decompress);
StreamReader reader = new StreamReader(compressionStream);
string outtext = reader.ReadToEnd();
reader.Close();
return outtext;
}
public static byte[] StreamToByte(Stream stream)
{
stream.Position = 0;
byte[] buffer = new byte[128];
using (MemoryStream ms = new MemoryStream())
{
while (true)
{
int read = stream.Read(buffer, 0, buffer.Length);
if (!(read > 0))
return ms.ToArray();
ms.Write(buffer, 0, read);
}
}
}
You can replace if(!(read > 0)) with if(read <= 0).
For some reason if(read <= 0) isn't displayed corret above.
For Stream:
static Stream CompressToStream(string data)
{
MemoryStream outstream = new MemoryStream();
GZipStream compressionStream =
new GZipStream(outstream, CompressionMode.Compress, true);
StreamWriter writer = new StreamWriter(compressionStream);
writer.Write(data);
writer.Close();
return outstream;
}
static string Decompress(Stream data)
{
data.Position = 0;
GZipStream compressionStream =
new GZipStream(data, CompressionMode.Decompress);
StreamReader reader = new StreamReader(compressionStream);
string outtext = reader.ReadToEnd();
reader.Close();
return outtext;
}
The MSDN Page on the function mentions the following:
If the current method throws an OutOfMemoryException, the reader's position in the underlying Stream object is advanced by the number of characters the method was able to read, but the characters already read into the internal ReadLine buffer are discarded. If you manipulate the position of the underlying stream after reading data into the buffer, the position of the underlying stream might not match the position of the internal buffer. To reset the internal buffer, call the DiscardBufferedData method; however, this method slows performance and should be called only when absolutely necessary.
Perhaps try calling DiscardBufferedData() before your ReadToEnd() and see what it does (I know you aren't getting the exception, but it's all I can think of...)?

Categories

Resources