Exception on Extracting the Zip file in C# - c#

I am working on Extraction Code to Extract Zip file, Using C# in winrt.
I am getting File from Local Drive here:
StorageFile file = await KnownFolders.PicturesLibrary.GetFileAsync("dostoyevsky-poor-folk.zip");
Stream zipMemoryStream = await file.OpenStreamForReadAsync();
var folder = ApplicationData.Current.LocalFolder;
// Create zip archive to access compressed files in memory stream
using (ZipArchive zipArchive = new ZipArchive(zipMemoryStream, ZipArchiveMode.Read))
{
// For each compressed file...
foreach (ZipArchiveEntry entry in zipArchive.Entries)
{
if (entry.Name == "")
{
// Folder
await CreateRecursiveFolder(folder, entry);
}
else
{
// File
await ExtractFile(folder, entry);
}
}
}
I am Extracting For folder here:
private async Task CreateRecursiveFolder(StorageFolder folder, ZipArchiveEntry entry)
{
var steps = entry.FullName.Split('/').ToList();
steps.RemoveAt(steps.Count() - 1);
foreach (var i in steps)
{
await folder.CreateFolderAsync(i, CreationCollisionOption.OpenIfExists);
folder = await folder.GetFolderAsync(i);
}
}
I am Extracting For File Here:
private async Task ExtractFile(StorageFolder folder, ZipArchiveEntry entry)
{
var steps = entry.FullName.Split('/').ToList();
steps.RemoveAt(steps.Count() - 1);
foreach (var i in steps)
{
folder = await folder.GetFolderAsync(i);
}
using (Stream fileData = entry.Open())
{
StorageFile outputFile = await folder.CreateFileAsync(entry.Name, CreationCollisionOption.ReplaceExisting);
using (Stream outputFileStream = await outputFile.OpenStreamForWriteAsync())
{
await fileData.CopyToAsync(outputFileStream);
await outputFileStream.FlushAsync();
}
}
}
When I try to use this I get this exception: 'System.NullReferenceException' .
The Exception getting line is the Last line of await outputFileStream.FlushAsync();
Some times I am getting same exception when I try to pick file from Local Drive.
Before Getting Exception the Debugger value of await outputFileStream.FlushAsync() looking like this.
Can you Help me out for this.
Thanks

Finally, It is Worked for me. Why because I am getting Null value while extraction Because of the package where I am going to extract files.
I am sure this is the perfect solution to Extract Zip file for windows store apps using c#.
Thanks

Related

How to Acess the Path of a file in Resources subfolder (Xamarin.Android)

I have EnglishSD.nbin file in Resources sub Models_folder I am accessing the path like this in my xamarin.android project but I am getting file not found Please help me with your suggestions thanks
var modelPath = AppDomain.CurrentDomain.BaseDirectory + "D:\\Foldername\\Project Name
\\Resources\\Models\\EnglishSD.nbin";
var sentenceDetector = new EnglishMaximumEntropySentenceDetector(modelPath);
var sentences = sentenceDetector.SentenceDetect(paragraph);
return sentences;
Error
Error: File not found Error
I'm not familiar with a ".nbin" file, but I would recommend putting it in the Android Assets folder instead.
You can read files from Assets like this:
public async Task<byte[]> ReadPdfFileAsync()
{
using (var fileStream = Assets.Open("pdf-file.pdf")
using (var memoryStream = new MemoryStream())
{
await fileStream.CopyToAsync(memoryStream);
return memoryStream.ToArray();
}
}

Download and upload DriveItem from shared OneDrive Folder with MS Graph SDK

I'm currently trying to implement several tasks that involve listing, uploading and downloading files from a shared OneDrive folder. This folder is accesible via the logged in users OneDrive (visible in his root folder). The listing part works pretty well so far, using this code:
string remoteDriveId = string.Empty;
private GraphServiceClient graphClient { get; set; }
// Get the root of the owners OneDrive
DriveItem ownerRoot = await this.graphClient.Drive.Root.Request().Expand("thumbnails,children($expand=thumbnails)").GetAsync();
// Select the shared folders general information
DriveItem sharedFolder = ownerRoot.Children.Where(c => c.Name == "sharedFolder").FirstOrDefault();
// Check if it is a remote folder
if(sharedFolder.Remote != null)
{
remoteDriveId = item.RemoteItem.ParentReference.DriveId;
// Get complete Information of the shared folder
sharedFolder = await graphClient.Drives[remoteDriveId].Items[sharedFolder.RemoteItem.Id].Request().Expand("thumbnails,children").GetAsync();
}
So obviously I need to retrieve the shared folders information from the OneDrive that shared it with the other OneDrive.
Next part for me is to list the contents of this shared folder, which also works pretty well like this:
foreach (DriveItem child in sharedFolder.Children)
{
DriveItem childItem = await graphClient.Drives[remoteDriveId].Items[child.Id].Request().Expand("thumbnails,children").GetAsync();
if(childItem.Folder == null)
{
string path = Path.GetTempPath() + Guid.NewGuid();
// Download child item to path
}
}
My problem starts with the "Download child item to path" part. There I want to download everything, that is not a folder to a temporary file. The problem is that OneDrive always answers my request with an error message, that the file was not found. What I tried so far is:
using (var stream = await graphClient.Drives[remoteDriveId].Items[childItem.Id].Content.Request().GetAsync())
using (var outputStream = new System.IO.FileStream(path, System.IO.FileMode.Create))
{
await stream.CopyToAsync(outputStream);
}
In another variant I tried to use the ID of the childItem ParentReference (but I think this will only lead me to the remote OneDrives ID of sharedFolder):
using (var stream = await graphClient.Drives[remoteDriveId].Items[childItem.ParentReference.Id].Content.Request().GetAsync())
using (var outputStream = new System.IO.FileStream(path, System.IO.FileMode.Create))
{
await stream.CopyToAsync(outputStream);
}
After Downloading the files I want to edit them and reupload them to a different path in the shared folder. That path is created by me (which allready works) like this:
DriveItem folderToCreate = new DriveItem { Name = "folderName", Folder = new Folder() };
await graphClient.Drives[remoteDriveId].Items[sharedFolder.Id].Children.Request().AddAsync(folderToCreate);
The upload then fails. I've tried it like this:
using (var stream = new System.IO.FileStream(#"C:\temp\testfile.txt", System.IO.FileMode.Open))
{
await graphClient.Drives[remoteDriveId].Items[sharedFolder.Id].Content.Request().PutAsync<DriveItem>(stream);
}
And also like this (which works if it is not a shared folder and I therefore use Drive instead of Drives):
using (var stream = new System.IO.FileStream(#"C:\temp\testfile.txt", System.IO.FileMode.Open))
{
string folderPath = sharedFolder.ParentReference == null ? "" : sharedFolder.ParentReference.Path.Remove(0, 12) + "/" + Uri.EscapeUriString(sharedFolder.Name);
var uploadPath = folderPath + "/" + uploadFileName;
await graphClient.Drives[remoteDriveId].Root.ItemWithPath(uploadPath).Content.Request().PutAsync<DriveItem>(stream);
}
I couldn't get the AddAsync method (like in the folder creation) to work because I don't know how to create a DriveItem from a Stream.
If somebody could point me in the right direction I would highly appreciate that! Thank you!
The request:
graphClient.Drives[remoteDriveId].Items[childItem.ParentReference.Id].Content.Request().GetAsync()
corresponds to Download the contents of a DriveItem endpoint and is only valid if childItem.ParentReference.Id refers to a File resource, in another cases it fails with expected exception:
Microsoft.Graph.ServiceException: Code: itemNotFound Message: You
cannot get content for a folder
So, to download content from a folder the solution would be to:
enumerate items under folder: GET /drives/{drive-id}/items/{folderItem-id}/children
per every item explicitly download its content if driveItem corresponds to a File facet: GET /drives/{drive-id}/items/{fileItem-id}/content
Example
var sharedItem = await graphClient.Drives[driveId].Items[folderItemId].Request().Expand(i => i.Children).GetAsync();
foreach (var item in sharedItem.Children)
{
if (item.File != null)
{
var fileContent = await graphClient.Drives[item.ParentReference.DriveId].Items[item.Id].Content.Request()
.GetAsync();
using (var fileStream = new FileStream(item.Name, FileMode.Create, System.IO.FileAccess.Write))
fileContent.CopyTo(fileStream);
}
}
Example 2
The example demonstrates how to download file from a source folder and upload it into a target folder:
var sourceDriveId = "--source drive id goes here--";
var sourceItemFolderId = "--source folder id goes here--";
var targetDriveId = "--target drive id goes here--";
var targetItemFolderId = "--target folder id goes here--";
var sourceFolder = await graphClient.Drives[sourceDriveId].Items[sourceItemFolderId].Request().Expand(i => i.Children).GetAsync();
foreach (var item in sourceFolder.Children)
{
if (item.File != null)
{
//1. download a file as a stream
var fileContent = await graphClient.Drives[item.ParentReference.DriveId].Items[item.Id].Content.Request()
.GetAsync();
//save it into file
//using (var fileStream = new FileStream(item.Name, FileMode.Create, System.IO.FileAccess.Write))
// fileContent.CopyTo(fileStream);
//2.Upload file into target folder
await graphClient.Drives[targetDriveId]
.Items[targetItemFolderId]
.ItemWithPath(item.Name)
.Content
.Request()
.PutAsync<DriveItem>(fileContent);
}
}
Instead of downloading/uploading file content, i think what you are actually after is DriveItem copy or move operations. Lets say there are files that needs to be copied from one (source) folder into another (target), then the following example demonstrates how to accomplish it:
var sourceDriveId = "--source drive id goes here--";
var sourceItemFolderId = "--source folder id goes here--";
var targetDriveId = "--target drive id goes here--";
var targetItemFolderId = "--target folder id goes here--";
var sourceFolder = await graphClient.Drives[sourceDriveId].Items[sourceItemFolderId].Request().Expand(i => i.Children).GetAsync();
foreach (var item in sourceFolder.Children)
{
if (item.File != null)
{
var parentReference = new ItemReference
{
DriveId = targetDriveId,
Id = targetItemFolderId
};
await graphClient.Drives[sourceDriveId].Items[item.Id]
.Copy(item.Name, parentReference)
.Request()
.PostAsync();
}
}
}

Received "The process cannot access the file because it is being used by another process" when creating .zip file using ZipFile

I am trying to create a large .zip file using the ZipFile library in C#.
Multiple music files are downloaded from URL by HttpClient and added in the zip loop.
For that, I follow for-loop > HttpClient to download music > add in zip > save zip.
Here, 30-35 music files will work perfectly. But i faced an issue when i have more than 35+ files. I want to create zip with minimum 500+ files.
I have an exception stored in logfile.txt.
The exception:
Action:The process cannot access the file because it is being used by another process. Controller: at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.File.InternalMove(String sourceFileName, String destFileName, Boolean checkHost)
at Ionic.Zip.ZipFile.Save()
at Groove.Libraries.Api.DonwloadMusic.<>c__DisplayClass5_0.<DownloadMusicFilesByScheduler>b__2(StudioEventEntryDetailsResponseModel y)
at System.Collections.Generic.List`1.ForEach(Action`1 action)
at Groove.Libraries.Api.DonwloadMusic.<>c__DisplayClass5_0.<DownloadMusicFilesByScheduler>b__0(StudioMusicDetails x)
at System.Collections.Generic.List`1.ForEach(Action`1 action)
at Groove.Libraries.Api.DonwloadMusic.DownloadMusicFilesByScheduler()
Exception is thrown by zip.Save(string.Format("{0}/{1}", tempPath, archiveFileName)); line.
Is there any problem with WebRequest or ZipFile Library?.
// Get list of music files url
EventMusicList eventEntryList = _globLib.GetEventMusicList(dbEvent.Id);
// zip file name
string archiveFileName = string.Format("{0}-{1}-Music.zip", eventEntryList.SeasonName,eventEntryList.EventName);
ZipFile zip;
// if zip Exists then get zip and add new music in this file OR create new zip
if (File.Exists(string.Format("{0}/{1}", tempPath, archiveFileName)))
{
zip = new ZipFile(string.Format("{0}/{1}", tempPath, archiveFileName));
}
else
{
zip = new ZipFile();
}
// Start : Looping of music files url
eventEntryList.StudioList.ForEach(
x => x.EntryList.ToList().Where(y => y.Document.Id != 0 && !y.Document.IsDownloaded).ToList().ForEach(y =>
{
// get music file url from dropbox.
DBB.GenerateAccessToken();
var _link = DBB.GetFileTemporaryLink(y.Document.RootPath, y.Document.FileName);
if (!_link.Equals(string.Empty))
{
// Get Stream from music url - function is created at bottom
Stream stream = GetStreamFromUrl(_link);
string fileExtension = Path.GetExtension(y.Document.FileUrl);
string fileName = y.EntryNumber != null
? string.Format("{0}-{1}{2}", y.EntryNumber, y.Title, fileExtension)
: string.Format("{0}{1}", y.Title, fileExtension);
if (zip.Entries.Where(z => z.FileName == fileName).Count() == 0)
{
// add in zip
zip.AddEntry(fileName, stream);
}
}
else
{
return;
}
// Check temporary path is exist or not, if not then create temporary folder
if (!Directory.Exists(tempPath))
{
Directory.CreateDirectory(tempPath);
}
this.LogRequest("Save:-BeforeSave", "DownloadMusicLib");
//Task t = Task.Run(() => { zip.Save(string.Format("{0}/{1}", tempPath, archiveFileName)); });
//t.Wait();
// Save zip file
zip.Save(string.Format("{0}/{1}", tempPath, archiveFileName));
this.LogRequest("Save:-AfterSave", "DownloadMusicLib");
})); // END : Looping of music files url
// New function to get stream from url
public static Stream GetStreamFromUrl(string url)
{
byte[] imageData = null;
Stream ms;
ms = null;
try
{
using (var wc = new System.Net.WebClient())
{
imageData = wc.DownloadData(url);
}
ms = new MemoryStream(imageData);
}
catch (Exception ex)
{
//forbidden, proxy issues, file not found (404) etc
}
return ms;
}
Screenshot of zip folder location, some are currepted
Here, I am getting temporary music file url from dropbox and get stream by using HttpClient.
When error occurs, zip file is courrpt. like '2018 - 2019-Washington IL Regional Competition-Music.zip.ugmf5uat.1a4'

Copy file from app installation folder to Local storage

I'm attempting to copy a file from the installed location of my Windows 8 app to it's local storage. I've been researching around and trying to do this to no avail. This is what I have come up with so far but I'm not sure where I'm going wrong.
private async void TransferToStorage()
{
try
{
// Get file from appx install folder
Windows.ApplicationModel.Package package = Windows.ApplicationModel.Package.Current;
Windows.Storage.StorageFolder installedLocation = package.InstalledLocation;
StorageFile temp1 = await installedLocation.GetFileAsync("track.xml");
// Read the file
var lines = await FileIO.ReadLinesAsync(temp1);
//Create the file in local storage
StorageFile myStorageFile = await localFolder.CreateFileAsync("track_iso.xml", CreationCollisionOption.ReplaceExisting);
// Write to it
await FileIO.WriteLinesAsync(myStorageFile, lines);
}
catch (Exception)
{
}
}
Any ideas?
Solved it myself. Here is the method for anyone else that encounters this question / problem:
private async void TransferToStorage()
{
// Has the file been copied already?
try
{
await ApplicationData.Current.LocalFolder.GetFileAsync("localfile.xml");
// No exception means it exists
return;
}
catch (System.IO.FileNotFoundException)
{
// The file obviously doesn't exist
}
// Cant await inside catch, but this works anyway
StorageFile stopfile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///installfile.xml"));
await stopfile.CopyAsync(ApplicationData.Current.LocalFolder);
}
No reason to read all the lines and write it to another file. Just use File.Copy.

Saving a stream containing an image to Local folder on Windows Phone 8

I'm currently trying to save an stream containing a jpeg image I got back from the camera to the local storage folder. The files are being created but unfortunately contain no data at all. Here is the code I'm trying to use:
public async Task SaveToLocalFolderAsync(Stream file, string fileName)
{
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFile storageFile = await localFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
using (IRandomAccessStream fileStream = await storageFile.OpenAsync(FileAccessMode.ReadWrite))
{
using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
{
using (DataWriter dataWriter = new DataWriter(outputStream))
{
dataWriter.WriteBytes(UsefulOperations.StreamToBytes(file));
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
await outputStream.FlushAsync();
}
}
}
public static class UsefulOperations
{
public static byte[] StreamToBytes(Stream input)
{
using (MemoryStream ms = new MemoryStream())
{
input.CopyTo(ms);
return ms.ToArray();
}
}
}
Any help saving files this way would be greatly appreciated - all help I have found online refer to saving text. I'm using the Windows.Storage namespace so it should work with Windows 8 too.
Your method SaveToLocalFolderAsync is working just fine. I tried it out on a Stream I passed in and it copied its complete contents as expected.
I guess it's a problem with the state of the stream that you are passing to the method. Maybe you just need to set its position to the beginning beforehand with file.Seek(0, SeekOrigin.Begin);. If that doesn't work, add that code to your question so we can help you.
Also, you could make your code much simpler. The following does exactly the same without the intermediate classes:
public async Task SaveToLocalFolderAsync(Stream file, string fileName)
{
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFile storageFile = await localFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
using (Stream outputStream = await storageFile.OpenStreamForWriteAsync())
{
await file.CopyToAsync(outputStream);
}
}

Categories