I have problem with handling files passed to my application in OnFileActivated(). First, I've registred specific file extention in Package.appminifest of my application, so after tap into specific file my application starts and run OnFileActivated function.
In my case file is archive zipped with System.IO.Compression.ZipArchive, but I think it's not crutial here. Beggining of my function looks as follow:
protected override async void OnFileActivated(FileActivatedEventArgs args) {
base.OnFileActivated(args);
var file = args.Files[0];
using (var archive = ZipFile.OpenRead(file.Path)) {
...
As some of you can expect I get an error when I'm trying to access file in last line. I also tried different solutions as copying file into local folder and then access it, but also without luck.
Question
Is there any way to do such thing? Or maybe I'm doing it completely wrong way?
Using the Path property will not be useful for a brokered file (such as you get from Activation). Use the constructor that takes a Stream instead.
Here is the correct answer:
protected override async void OnFileActivated(FileActivatedEventArgs args) {
base.OnFileActivated(args);
var file = (StorageFile)args.Files[0];
using (var archive = new ZipArchive(await file.OpenStreamForReadAsync())) {
...
I haven't noticed before that ZipArchive have constructor which takes stream as a parameter.
Related
I would like to associate a GUID with my StorageFile, to make it easier to test whether or not two files are derived from the same source.
I'm trying to save the GUID in a file property:
private static string GuidProperty = "System.Comment"; // also tried "System.Subject".
static public async Task<Guid> GetGuidAsync( StorageFile file)
{
var properties = await file.Properties.RetrievePropertiesAsync(new string[] { GuidProperty });
if (!(properties[GuidProperty] is string guidString)) {
throw new InvalidOperationException("Missing GUID on file.");
}
return new Guid(guidString);
}
static public async Task InitializeGuidAsync( StorageFile file)
{
var properties = await file.Properties.RetrievePropertiesAsync(new string[] { GuidProperty });
properties[GuidProperty] = Guid.NewGuid().ToString();
await file.Properties.SavePropertiesAsync(properties);
}
This doesn't work. When it gets to SavePropertiesAsync it throws a COMException saying "Error HRESULT E_FAIL as been returned from a call to a COM component."
The file is an SQLite database in the app directory, with a custom file extension.
How can I tag this file with a GUID?
P.S. After some poking around ... maybe the problem is that I have not registered the file property handlers for the custom file type. Not sure how to do that yet.
The problem is that the custom file type does not support storing of properties.
Properties are stored inside the file and are written and read by Windows 10 using property handlers that you implement.
The following page discusses properties in Windows 10: https://msdn.microsoft.com/en-us/library/windows/desktop/bb776859(v=vs.85).aspx
With respect to using SQLite as a document format, unfortunately, the SQLite file can only be accessed when it is in the app dir. Consequently it is highly inefficient to support file properties because reading or writing the property requires copying the file to the app dir and back.
As it was common to guess what kind of reason for this exception. But let me explain the exact scenario which am facing . Please find the overview of my code block.
Task.Factory.StartNew(()=> Method1());
private void Method1()
{
//A process which loads the file and uploads it to server. If the file was large, it will take some amount of time.
using (var fileStream = System.IO.File.OpenRead(filePath))
{
//Upload file
}
//Once uploads deletes from local.
File.Delete(path);
}
Before uploading the file delete method was called as I have used separate tasks . So I get the exception that process cannot access the file.
I should delete the file once upload was over. Need some suggestions on that.
TPL Continuewith
you can also make use of contnuewith over here because
you want to updload file
once update done you want to delete file
than you can do this
Task t =Task.Factory.StartNew(()=> Method1());//remove delete file form method one
t.ContinueWith((as)=> {File.Delete(path);} );
there might be syntax error in above code so please solve it in visual studio
Singling Construct
As you are updloading and delete file on different threds that I suggest you
make use of signaling construct
public class test
{
private static AutoResetEvent event_2 = new AutoResetEvent(false);
public void uploadfile()
{
///do file updating
//than give signale
event_2.set();
}
public void deletefile()
{
event_2.WaitOne();
//delete file
}
}
it doesn't seem thread issue , it look like file you want to delete is not present so its better you check file exists or not by file exits method
if (File.Exists(path))
{
File.Delete(path);
}
I have the following code:
// get location where application data director is located
var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
// create dir if it doesnt exist
var folder = System.IO.Path.Combine(appData, "SomeDir");
if (System.IO.Directory.Exists(folder) == false)
System.IO.Directory.CreateDirectory(folder);
// create file if it doesnt exist
var file = System.IO.Path.Combine(folder, "test.txt");
if(System.IO.File.Exists(file)== false)
System.IO.File.Create(file);
// write something to the file
System.IO.File.AppendAllText(file,"Foo");
This code crashes on the last line (An unhandled exception of type 'System.IO.IOException' occurred in mscorlib.dll). If I put a Thread.Sleep(400) after creating the file the code works great. What is the proper way of waiting until the file is created?
P.S.
I am using .net framework 3.5
Even if I wait it crashes :/
The reason for that is because File.Create is declared as:
public static FileStream Create(
string path
)
It returns a FileStream. The method is supposed to be used to create and open a file for writing. Since you never dispose of the returned FileStream object you're basically placing your bets on the garbage collector to collect that object before you need to rewrite the file.
So, to fix the problem with the naive solution you should dispose of that object:
System.IO.File.Create(file).Dispose();
Now, the gotcha here is that File.AppendAllText will in fact create the file if it does not exist so you don't even need that code, here is your full code with the unnecessary code removed:
// get location where application data director is located
var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
// create dir if it doesnt exist
var folder = System.IO.Path.Combine(appData, "SomeDir");
System.IO.Directory.CreateDirectory(folder);
// write something to the file
var file = System.IO.Path.Combine(folder, "test.txt");
System.IO.File.AppendAllText(file,"Foo");
Directory.CreateDirectory will likewise not crash if the folder already exists so you can safely just call it.
There is no need to create the file if you intend to use File.AppendAllText
About the root cause for the error, and a preferred way to write to files in general:
The file was created, and returned a stream that you didn't use/close. best method should be to use this stream to write to the file.
using (FileStream fs = File.Create(file))
{
fs.Write("What ever you need to write..");
}
I have a program that roughly does this:
open a file to read from it.
close the file
Start a filewatcher to watch for changes in the file.
As soon as a change is detected, the filewatcher's EnableRaisingEvents flag is set to false and the process repeats from Step 1.
The problem is, after going from step 4 to step 1, it cannot read the file saying that it is being used by another Process.
Error I receive:
Unhandled Exception: System.IO.IOException: The process cannot access the file 'c:\test.xml' because it is being used by another process.
Whats going wrong? does the reader from Step 1 of my program still have the file open, or is some entirely different process accessing the file, or is it that filewatcher is still watching the file after moving to Step 1 from 4, despite setting the flag to false?
If your code is similar to this:
[STAThread]
static void Main(string[] args)
{
string file = "temp.txt";
ReadFile(file);
FileSystemWatcher fswatcher = new FileSystemWatcher(".\\");
fswatcher.Changed += delegate(object sender, FileSystemEventArgs e)
{
ReadFile(e.FullPath);
};
while (true)
{
fswatcher.WaitForChanged(WatcherChangeTypes.Changed);
}
}
private static void ReadFile(string file)
{
Stream stream = File.OpenRead(file);
StreamReader streamReader = new StreamReader(stream);
string str = streamReader.ReadToEnd();
MessageBox.Show(str);
streamReader.Close();
stream.Close();
}
If you are editing the file via notepad, then, when you click the save button, it keeps the file open, while as if when you just close the program and click save it doesn't. I do no know if this is a bug or an undocumented feature of notepad, but this just might be your problem. One way to fix this is to do the following:
In your anonymous delegate, or wherever you execute the call to ReadFile() call Thread.Sleep(1000), to have the program wait before reading the file and your code should work fine.
You can use a tool like Process Explorer from http://www.sysinternals.com to see who has the open handle to the process
The file is most likely held open by whatever caused the change notification to fire in the first place.
Beside other answers it is possible that when FileWatcher reacts file it not yet closed by that app. In step 1 try not to fail immediately but try several attempts with small delay.
Note: even if "file.txt" is open in Notepad, this code still works, because it is opening for read.
using System;
using System.IO;
class Program
{
static void Main(string[] args)
{
ReadFromFile(#"C:\file.txt");
Console.ReadLine();
}
static void ReadFromFile(string filename)
{
string line;
using (StreamReader sr = File.OpenText(filename))
{
line = sr.ReadLine();
while (line != null)
{
Console.WriteLine(str);
line = sr.ReadLine();
}
sr.Close();
}
}
}
Or just:
string text = System.IO.File.ReadAllText(#"C:\file.txt");
The problem is that the FileSystemWatcher tells you immediately when the file was created. It doesn't wait for the file to be released.
For instance, when you copy a large file which takes 3 seconds to copy, so you have to open the file after that.
http://www.codeproject.com/Questions/461666/FileSystemWatcher-issue-in-windows-application
Wait until file is unlocked in .NET
There are a number of things that could be going on.
First, make sure you properly dispose of the file writer (close isn't good enough) by utilizing the using clause around everything that implements IDisposable.
Second, it you are simply reading, make sure you have the correct flags set when opening the file.
To go any further it would help if you provided a code block which showed how you were accomplishing this; particularly around the reading of the file
You can use this MS utility openfiles to obtain list of opened files and understand who has opened the file.
openfiles /query
Also it allow to disconnect files opened by network users.
openfiles /disconnect /id XXXX
If you want use it for local PC you should set Maintain Objects List global flag:
openfiles /local on
Follow the link to get more details.
I simply want to write the contents of a TextBox control to a file in the root of the web server directory... how do I specify it?
Bear in mind, I'm testing this locally... it keeps writing the file to my program files\visual studio\Common\IDE directory rather than my project directory (which is where I assume root is when the web server fires off).
Does my problem have something to do with specifying the right location in my web.config? I tried that and still no go...
Thanks much...
protected void TestSubmit_ServerClick(object sender, EventArgs e)
{
StreamWriter _testData = new StreamWriter("data.txt", true);
_testData.WriteLine(TextBox1.Text); // Write the file.
_testData.Close(); // Close the instance of StreamWriter.
_testData.Dispose(); // Dispose from memory.
}
protected void TestSubmit_ServerClick(object sender, EventArgs e)
{
using (StreamWriter _testData = new StreamWriter(Server.MapPath("~/data.txt"), true))
{
_testData.WriteLine(TextBox1.Text); // Write the file.
}
}
Server.MapPath takes a virtual path and returns an absolute one. "~" is used to resolve to the application root.
There are methods like WriteAllText in the File class for common operations on files.
Use the MapPath method to get the physical path for a file in your web application.
File.WriteAllText(Server.MapPath("~/data.txt"), TextBox1.Text);
protected void TestSubmit_ServerClick(object sender, EventArgs e)
{
using (StreamWriter w = new StreamWriter(Server.MapPath("~/data.txt"), true))
{
w.WriteLine(TextBox1.Text); // Write the text
}
}
Keep in mind you'll also have to give the IUSR account write access for the folder once you upload to your web server.
Personally I recommend not allowing write access to the root folder unless you have a good reason for doing so. And then you need to be careful what sort of files you allow to be saved so you don't inadvertently allow someone to write their own ASPX pages.