i've an issue in my application. I'm trying to send an image into FTP server. I'm able to connect with server, authenticate, and other. But when i try to send file, if the file is big (usually bigger than 40-50kb) i got System.ObjectDisposedException.
This is the code that i use to send:
public async Task <byte[]> GetResultingBuffer(IRandomAccessStreamWithContentType readStream, IBuffer buffer)
{
var resultingBuffer = new byte[0];
while (true)
{
IBuffer readBuffer = await readStream.ReadAsync(buffer, 1024, InputStreamOptions.Partial);
if (readBuffer.Length == 0) break;
resultingBuffer = resultingBuffer.Concat(readBuffer.ToArray()).ToArray();
}
return resultingBuffer;
}
public async Task UploadFileAsync(StorageFile file, string destination)
{
using (var stream = await OpenWriteAsync(destination))
{
//
// A more efficient way, maybe a DataReader can be used here
using (var readStream = await file.OpenReadAsync())
{
var buffer = new byte[1024].AsBuffer();
var resultingBuffer = new byte[0];
resultingBuffer = await GetResultingBuffer(readStream, buffer);
await stream.WriteAsync(resultingBuffer.AsBuffer());
await stream.FlushAsync();
}
}
}
I tried to edit it, before editing GetResultingBuffer was not a task, but a cycle inside UploadFileAsnc. How can i prevent to dispose the buffer? Is there another solution? Thanks!
I solved it in this way
using (var readStream = await file.OpenReadAsync())
{
var buffer = new byte[3000000].AsBuffer();
//var resultingBuffer = new byte[10000000];
Debug.Write("-------");
//while (true)
//{
IBuffer readBuffer = await readStream.ReadAsync(buffer, 3000000, InputStreamOptions.Partial);
//if (readBuffer.Length == 0) break;
//resultingBuffer = resultingBuffer.Concat(readBuffer.ToArray()).ToArray();
//}
// await stream.WriteAsync(resultingBuffer.AsBuffer());
var resultingBuffer = new byte[readBuffer.Length];
readBuffer.CopyTo(resultingBuffer);
await stream.WriteAsync(resultingBuffer.AsBuffer());
}
Debug.Write("-------");
await stream.FlushAsync();
Related
I want to be able to upload multiple files via FileInput but got stuck when it comes to parallelism.
I simply want to show the user a progress-bar (depending on overall read bytes) and afterwards a simple list of what has already been processed.
Currently my callback is looking like this:
private async Task HandleInputFileChange(InputFileChangeEventArgs fileChangeEventArgs)
{
_filesProcessed.Clear();
_alreadyRead = 0;
var browserFiles = fileChangeEventArgs.GetMultipleFiles();
_max = browserFiles.Sum(bf => bf.Size);
await Task.WhenAll(browserFiles.Select(browserFile => Task.Run(async () =>
{
var trustedFileName = Path.GetRandomFileName();
var filePath = Path.Combine(HostEnvironment.ContentRootPath, HostEnvironment.EnvironmentName, FolderName, trustedFileName);
await using var fileStream = new FileStream(filePath, FileMode.Create);
await using var readStream = browserFile.OpenReadStream(AllowedFileSize);
int bytesRead;
var readBuffer = new byte[1024 * 10];
while ((bytesRead = await readStream.ReadAsync(readBuffer)) != 0)
{
_alreadyRead += bytesRead;
await fileStream.WriteAsync(readBuffer, 0, bytesRead);
await InvokeAsync(StateHasChanged);
}
_filesProcessed.Add(browserFile);
})));
}
However, with this code I mostly end up in a NullReferenceException at
Microsoft.AspNetCore.Components.Server.Circuits.RemoteJSDataStream.ReceiveData(RemoteJSRuntime runtime, Int64 streamId, Int64 chunkId, Byte[] chunk, String error)
Currently I'm not even sure if this is possible to do or not as it may seem to be an issue with how things get synchronized by the framework.
I´m using Windows.Media.SpeechSynthesis for TTS and playing an audio signal works fine in my WPF application. I have wanted to save an audio signal but if I call StorageFolder I get an error: HRESULT: 0x80073D54 - The process has no package identity. How to fix it? The whole code is below. I would also like to know what rights apply to the use of an audio file from Win 10 TTS? I didn't find it anywhere - but I wasn't looking for that much...
private async void Talk(string text)
{
var stream = await speechSynthesizer.SynthesizeTextToStreamAsync(text);
StorageFolder localfolder = ApplicationData.Current.LocalFolder;
StorageFile sampleFile = await localfolder.CreateFileAsync("sample.wav", CreationCollisionOption.ReplaceExisting);
using (var reader = new DataReader(stream))
{
await reader.LoadAsync((uint)stream.Size);
IBuffer buffer = reader.ReadBuffer((uint)stream.Size);
await FileIO.WriteBufferAsync(sampleFile, buffer);
}
}
Finally, I have found a solution, how to save a stream from tts into *.wav or to *.mp3 by Naudio. I don´t know if it is clear but it is functional:
public bool ByteArrayToFile(string fileName, byte[] byteArray)
{
try
{
using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
fs.Write(byteArray, 0, byteArray.Length);
return true;
}
}
catch (Exception ex)
{
Console.WriteLine("Exception caught in process: {0}", ex);
return false;
}
}
private async Task SaveAudio(string text)
{
var stream = await speechSynthesizer.SynthesizeTextToStreamAsync(text);
using (var reader = new DataReader(stream))
{
await reader.LoadAsync((uint)stream.Size);
IBuffer buffer = reader.ReadBuffer((uint)stream.Size);
DataReader dataReader = DataReader.FromBuffer(buffer);
byte[] bytes = new byte[buffer.Length];
dataReader.ReadBytes(bytes);
//ByteArrayToFile("sample.wav", bytes);
ConvertWavStreamToMp3File(bytes, TB_File.Text);
MessageBox.Show("Audio was saved to file: " + TB_File.Text, "Info");
}
}
public static void ConvertWavStreamToMp3File(byte[] wavFile, string savetofilename)
{
using (var retMs = new MemoryStream())
using (var ms = new MemoryStream(wavFile))
using (var rdr = new WaveFileReader(ms))
using (var wtr = new LameMP3FileWriter(savetofilename, rdr.WaveFormat, LAMEPreset.VBR_90))
{
rdr.CopyTo(wtr);
}
}
I am working on xamarin.forms application. I want to download multiple files simultaneously using HttpClient. If there is multiple files then I am getting : System.IO.IOException:Sharing violation on path . Is there anything that has to be improved ?
Here is my code for downloading files :
public async Task DownloadFileAsync(string sourceUrl, string filePathWhereToSave, CancellationTokenSource cts)
{
Exception error = null;
bool isCancelled = false;
try
{
if (!downloadingTasks.ContainsKey(sourceUrl))
downloadingTasks.Add(sourceUrl, cts);
var token = cts.Token;
var response = await _client.GetAsync(sourceUrl, HttpCompletionOption.ResponseHeadersRead, token);
response.EnsureSuccessStatusCode();
string fileName = filePathWhereToSave.Substring(filePathWhereToSave.LastIndexOf('/'));
string directory = filePathWhereToSave.Substring(0, filePathWhereToSave.LastIndexOf('/'));
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
Directory.CreateDirectory(directory);
var totalData = response.Content.Headers.ContentLength.GetValueOrDefault(-1L);
var canSendProgress = totalData != -1L;
await Task.Run(async() =>
{
using (var fileStream = OpenStream(filePathWhereToSave))
{
using (var stream = await response.Content.ReadAsStreamAsync())
{
var totalRead = 0L;
var buffer = new byte[bufferSize];
var isMoreDataToRead = true;
do
{
var read = await stream.ReadAsync(buffer, 0, buffer.Length, token);
if (read == 0)
isMoreDataToRead = false;
else
{
await fileStream.WriteAsync(buffer, 0, read);
totalRead += read;
if (canSendProgress)
{
//var progress = ((totalRead * 1d) / (totalData * 1d) * 100);
MessagingCenter.Send<DownloadFileProgressChangedMessage>(new DownloadFileProgressChangedMessage(sourceUrl, totalRead, totalData, 0), MessageNameConstants.DownloadFileProgressChangedMessage);
}
}
} while (isMoreDataToRead);
}
}
});
}
catch (OperationCanceledException ex)
{
isCancelled = true;
}
catch (Exception e)
{
error = e;
System.Diagnostics.Debug.WriteLine(e.ToString());
}
finally
{
MessagingCenter.Send<DownloadCompletedMessage>(new DownloadCompletedMessage(sourceUrl, filePathWhereToSave, error, isCancelled), MessageNameConstants.DownloadCompletedMessage);
if (downloadingTasks.ContainsKey(sourceUrl))
downloadingTasks.Remove(sourceUrl);
}
}
This may be happening because the file is being locked by the reading stream, so the writing stream can't be created and you get the exception.
To avoid it you could enable read/write access with the class FileStream .
FileStream fileStream = new FileStream(filePathWhereToSave,
FileMode.OpenOrCreate,
FileAccess.ReadWrite,
FileShare.None);
Or use StreamWriter
using (var writer = new StreamWriter(filePathWhereToSave))
{
// do work here.
}
BTW , what is OpenStream ? I can't find it in any assembly, is it included in a third-party library ?
Refer to
https://stackoverflow.com/a/23779697/8187800
https://stackoverflow.com/a/11541330/8187800
I would like to have a method which takes as an input a System.IO.Stream and use it to write data from it to file. So far I have the following:
public async Task SaveStreamToFileX(Stream stream, string filePath, IProgress<long> progress)
{
var folder = await StorageFolder.GetFolderFromPathAsync(Path.GetDirectoryName(filePath));
var fileName = Path.GetFileName(filePath);
StorageFile file = await folder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists);
var istream = stream.AsInputStream();
var canRead = stream.CanRead; //this returns true
using (var reader = new DataReader(istream))
{
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
{
using (DataWriter writer = new DataWriter(outputStream))
{
IBuffer buffer;
long readBytes = 0;
const int bufferSize = 8192;
while ((buffer = reader.ReadBuffer(bufferSize)).Length > 0) //exception System.Exception with message: Out of range ...
{
writer.WriteBuffer(buffer);
readBytes += bufferSize;
progress.Report(readBytes);
}
}
}
}
}
}
Problem is, that an exception (Out of range) is thrown when I try to read data in while cycle (first read). Stream should have data. I am not sure if so long code is neccesarry, if somebody has better solution it would be great.
Side note:
If I try await reader.LoadAsync(50) it returns 50. I am not sure what LoadAsync should do. Maybe I have to call it before read to prepare data for the read? I will investigate this further ...
Also, the Stream.CanRead returns true.
The problem was not with converting streams as I orginally thought. It was just lack of the knowlidge how the work with files is done in WinRT (the docs from microsoft are really terrible in my opinion).
In the end with help of my collegue with tried several ways and end up with the following:
public async Task SaveStreamToFile(Stream stream, string filePath, IProgress<long> progress )
{
var folder = await StorageFolder.GetFolderFromPathAsync(Path.GetDirectoryName(filePath));
var fileName = Path.GetFileName(filePath);
StorageFile file = await folder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists);
var istream = stream.AsInputStream();
using (var reader = new DataReader(istream))
{
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
{
using (DataWriter writer = new DataWriter(outputStream))
{
long writtenBytes = 0;
const int bufferSize = 8192;
uint loadedBytes = 0;
while ((loadedBytes = (await reader.LoadAsync(bufferSize))) > 0) //!!!
{
IBuffer buffer = reader.ReadBuffer(loadedBytes);
writer.WriteBuffer(buffer);
uint tmpWritten = await writer.StoreAsync(); //!!!
writtenBytes += tmpWritten;
progress.Report(writtenBytes);
}
}
}
}
}
}
I would like to see some simpler implementation, but this works. The problems were that LoadAsync was missing (which seems to be necessary to call) and during write operation the StoreAsync must be called in order to commit the data (flushing was not sufficient).
I hope this help somebody.
I would advise against that kind of code and instead take advantage of Windows Runtime Interop extension methods. That would produce a neater and more readable code, ex :
private async Task CopyToTempFile(Stream stream, string temporaryFileName) {
var file = await ApplicationData.Current.TemporaryFolder.CreateFileAsync(temporaryFileName, CreationCollisionOption.ReplaceExisting);
using (var outputstream = await file.OpenStreamForWriteAsync()) {
await stream.CopyToAsync(outputstream);
}
}
The code:
private async Task<int> Save()
{
StorageFile file = await DownloadsFolder.CreateFileAsync("a.exe");
IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite);
DataWriter writer = new DataWriter(stream);
byte[] buffer = new byte[4096];
writer.WriteBytes(buffer);
await writer.StoreAsync();
await writer.FlushAsync(); //Hang for a long time
writer.Dispose();
return 1001; //eventually it can get to this line, no exception is thrown
}
Edit:
It is found on Win8 CP build 8250, after upgraded to build 8375, the problem goes away. So I guess it is a bug that have been fixed either in winrt or win8.
You can try something more like this:
using (var fs = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (var outStream = fs.GetOutputStreamAt(0))
{
using (var dataWriter = new DataWriter(outStream))
{
byte[] buffer = new byte[4096];
dataWriter.WriteBytes(buffer)
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
await outStream.FlushAsync();
}
}