I have a situation where my file changes sizes (things added and deleted frequently). The user has the option to save their file. However, if they save their file OVER an existing file that is larger (which they are allowed to do), then it scrambles the file by leaving extra crud at the end from the file that was larger.
For example, I have the following code:
// The user saves their data to disk. No problem.
FileSavePicker savePicker = new FileSavePicker();
savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
savePicker.FileTypeChoices.Add("Plain Text", new List<string>() { ".txt" });
savePicker.SuggestedFileName = "New Document";
StorageFile file = await savePicker.PickSaveFileAsync();
if (file != null)
{
using (var stream = await file.OpenStreamForWriteAsync())
{
using (var sw = new StreamWriter(stream))
{
sw.Write("ABCDEFGH");
}
}
}
// The user saves their data to disk again, overwriting their first file.
FileSavePicker savePicker2 = new FileSavePicker();
savePicker2.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
savePicker2.FileTypeChoices.Add("Plain Text", new List<string>() { ".txt" });
savePicker2.SuggestedFileName = "New Document";
StorageFile file2 = await savePicker2.PickSaveFileAsync();
if (file2 != null)
{
using (var stream = await file2.OpenStreamForWriteAsync())
{
using (var sw = new StreamWriter(stream))
{
sw.Write("1234");
}
}
}
}
When this code is finished, my resulting file is 1234EFGH, not 1234, as I had expected.
What am I doing wrong? I can't just delete the file between the two calls or the StorageFile will crash on OpenStreamAForWriteAsync(...)
To cut tail of the stream if you overwriting the existing file adjust length of the stream to match last position (make sure to flush stream/writer before updating length):
stream.SetLength(stream.Position);
Related
var sdcardpath = Android.OS.Environment.ExternalStorageDirectory.Path;
var filepath = System.IO.Path.Combine(sdcardpath, "first.html");
System.IO.StreamWriter writer = new StreamWriter(filepath, true);
if (!System.IO.File.Exists(filepath))
{
writer.Write(htmltext);
}
else
{
var txt = System.IO.File.ReadAllText(filepath);
}
In This Way I want to read an html from my local storage But while readalltext am getting exception
System.IO.IOException: Sharing violation on path /storage/emulated/0/first.html
When you do this
System.IO.StreamWriter writer = new StreamWriter(filepath, true);
it opens/creates a file at filepath. So after this the file always exists (given the path is correct and permissions allow). Then you try to read it but you have it open for writing so this will not be allowed.
If you're trying to see if the file exists and if not, write to it, then move the StreamWriter creation inside the check
if (!System.IO.File.Exists(filepath))
{
using (var writer = new StreamWriter(filepath, true))
{
writer.Write(htmltext);
}
}
else
{
var txt = System.IO.File.ReadAllText(filepath);
}
I'm trying to save a file to the Documents folder using PickSaveFileAndContinue() method in WP 8.1 RT. Everything is happening fine except the file which gets saved is empty.
When I get the file returned from the following code in OnActivated() method, it's size is zero.
Anyone?
var database = await FileHelper.GetFileAsync(ApplicationData.Current.LocalFolder, DATABASE_NAME);
FileSavePicker savePicker = new FileSavePicker();
savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
savePicker.FileTypeChoices.Add("Database File", new List<string>() { ".db" });
savePicker.DefaultFileExtension = ".db";
savePicker.SuggestedFileName = DATABASE_NAME;
savePicker.SuggestedSaveFile = database;
After the location is picked, the following code is executed in App.xaml.cs. I tried doing this inside the same page using a ContinuationManager. But then result is same.
protected async override void OnActivated(IActivatedEventArgs args)
{
byte[] buffer = null;
if(args!=null)
{
if(args.Kind == ActivationKind.PickSaveFileContinuation)
{
var file = ((FileSavePickerContinuationEventArgs)args).File;//This is empty
using (IRandomAccessStreamWithContentType stream = await file.OpenReadAsync())
{
buffer = new byte[stream.Size];
using (DataReader reader = new DataReader(stream))
{
await reader.LoadAsync((uint)stream.Size);
reader.ReadBytes(buffer);
}
}
if (file != null)
{
CachedFileManager.DeferUpdates(file);
await FileIO.WriteBytesAsync(file, buffer);
Windows.Storage.Provider.FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(file);
}
}
}
base.OnActivated(args);
}
That's expected. PickSaveFileAndContinue doesn't know what the app wants to save. It just provides an empty StorageFile. The app can then write whatever contents it wants to save into the file.
I am attempting to download a bunch of files that I am zipping up(archiving) via ZipoutputStream.
using (var zipStream = new ZipOutputStream(outputMemStream))
{
foreach (var documentIdString in documentUniqueIdentifiers)
{
...
var blockBlob = container.GetBlockBlobReference(documentId.ToString());
var fileMemoryStream = new MemoryStream();
blockBlob.DownloadToStream(fileMemoryStream);
zipStream.SetLevel(3);
fileMemoryStream.Position = 0;
ZipEntry newEntry = new ZipEntry(document.FileName);
newEntry.DateTime = DateTime.Now;
zipStream.PutNextEntry(newEntry);
fileMemoryStream.Seek(0, SeekOrigin.Begin);
StreamUtils.Copy(fileMemoryStream, zipStream, new byte[4096]);
zipStream.IsStreamOwner = false; // False stops the Close also Closing the underlying stream.
}
outputMemStream.Seek(0, SeekOrigin.Begin);
return outputMemStream;
}
In my controller I am returning the following code that should download the Zip file i created in the previous example. The controller actions downloads the file as it should in the browser, but the Archived File is empty. I can see the content length populated returning from the method above...
file.Seek(0, SeekOrigin.Begin);
return File(file, "application/octet-stream", "Archive.zip");
Does anyone have any idea why my file that is returned by my controller is empty or corrupt?
I believe you need to close your entries and your final zip stream. You should also using and dispose all of your streams. Try this:
using (var zipStream = new ZipOutputStream(outputMemStream))
{
zipStream.IsStreamOwner = false;
// Set compression level
zipStream.SetLevel(3);
foreach (var documentIdString in documentUniqueIdentifiers)
{
...
var blockBlob = container.GetBlockBlobReference(documentId.ToString());
using (var fileMemoryStream = new MemoryStream())
{
// Populate stream with bytes
blockBlob.DownloadToStream(fileMemoryStream);
// Create zip entry and set date
ZipEntry newEntry = new ZipEntry(document.FileName);
newEntry.DateTime = DateTime.Now;
// Put entry RECORD, not actual data
zipStream.PutNextEntry(newEntry);
// Copy date to zip RECORD
StreamUtils.Copy(fileMemoryStream, zipStream, new byte[4096]);
// Mark this RECORD closed in the zip
zipStream.CloseEntry();
}
}
// Close the zip stream, parent stays open due to !IsStreamOwner
zipStream.Close();
outputMemStream.Seek(0, SeekOrigin.Begin);
return outputMemStream;
}
EDIT - you should remove:
// Reset position of stream
fileMemoryStream.Position = 0;
Pretty sure that's the problem.
I have got a code from this link:
http://www.codeproject.com/Tips/515704/Archive-Multiple-Files-In-Zip-Extract-Zip-Archive
that compresses and extracts a file in zip format.
However the compressing part in the code just creates an empty zipfile, so how can i add files programmatically in this zip archieve?
i have checked the doc for the ziparchieve class and it has a method for .net called CreateEntryFromFile(String, String) , however this method doesn't apply for .net windows store version.
this is the code we are concerned with:
private async void ZipClick(object sender, RoutedEventArgs e)
{
FileSavePicker picker = new FileSavePicker();
picker.FileTypeChoices.Add("Zip Files (*.zip)", new List<string> { ".zip" });
picker.SuggestedStartLocation = PickerLocationId.Desktop;
picker.SuggestedFileName = "1";
zipFile = await picker.PickSaveFileAsync();
using (var zipStream = await zipFile.OpenStreamForWriteAsync())
{
using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create))
{
foreach (var file in storeFile)
{
ZipArchiveEntry entry = zip.CreateEntry(file.Name);
using (Stream ZipFile = entry.Open())
{
byte[] data = await GetByteFromFile(file);
ZipFile.Write(data, 0, data.Length);
}
}
}
}
}
I misunderstood the sample code, it actually can archive the the files you pass it for the first time, but i'm not sure if the same method can be used to add to add other files in the same zip file later.
public async void zipit(StorageFile zipFile, StorageFile file)
{
using (var zipToOpen = await zipFile.OpenStreamForWriteAsync())
{
using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update))
{
ZipArchiveEntry readmeEntry = archive.CreateEntry(file.Name);
using (Stream writer = readmeEntry.Open())
{
//writer.WriteLine("Information about this package.");
//writer.WriteLine("========================");
byte[] data = await GetByteFromFile(file);
writer.Write(data, 0, data.Length);
}
}
}
}
where "zipFile" is the file you have chose to archive in (destination ) and "file" is the original non zipped file.
I have such strange problem with append line ... I'm quite new with developing for Windows phone, but I program¨m in c sharp for some time. So I tried to create file for saving users data (simple lines in txt file). I use this codes:
byte[] filebytes = System.Text.Encoding.UTF8.GetBytes("blablablabla");
StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
var folder = await local.CreateFolderAsync("Data", CreationCollisionOption.OpenIfExists);
var file = await folder.CreateFileAsync("data.txt", CreationCollisionOption.OpenIfExists);
using (var s = await file.OpenStreamForWriteAsync())
{
s.Write(filebytes, 0, filebytes.Length);
}
for writing to file and
StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
if (local != null)
{
var folder = await local.GetFolderAsync("Data");
var file = await folder.OpenStreamForReadAsync("data.txt");
using (StreamReader sr = new StreamReader(file))
{
string line;
while ((line = sr.ReadLine()) != null)
{
TextBlock.Text = line;
}
}
}
to read from it. I also tried many others possibility how to read/write to files, but all ended with the same result - all data lost, and in file was only last line. First I thought that problem will be in offset here s.Write(filebytes, 0, filebytes.Length); but in other methods it was in other way and nothing helped. Right now I have improved code, that it works, but read all data and write it all at once is not solution. Thanks for any advice.
Replace
s.Write(filebytes, 0, filebytes.Length);
With
await writer.WriteLineAsync("new entry");