File.Copy and WPF - c#

I have a little problem with the File.Copy method in WPF, my code is very simple and I get an exception when I run it,
Could not find a part of the path 'Images\37c31987-52ee-4804-8601-a7b9b4d439fd.png'.
where Images is a relative folder.
Here is my code, as I said simple and the same code works fine in a console application, no problem at all.
string filenamae = System.IO.Path.Combine(images, Guid.NewGuid().ToString() + System.IO.Path.GetExtension(imageFile)); ;
System.IO.File.Copy(imageFile, filenamae);
this.ImageLocation = string.Empty;
So if any can help, thanks.

Does the images folder exist? File.Copy doesn't create it automatically.
Do you know what your current directory is? File open/save boxes can change that. So it's always safer to work with absolute paths.
Do a
Path.GetFullPath(filename)
and see where that points to. Is it the right location?

If you use the absolute instead of the relative path, does it work then?

Before you access a file, you should call System.IO.File.Exists(). It's not clear from your error description if the origin file exists or not before the copy.
If you don't specify an absolute path, your relative path with often be resolved from unexpected places, usually the current working directory of the process. Calling this method may tell you were the process is currently running:
System.IO.Directory.GetCurrentDirectory()
You should never make assumptions about the current working directory of a running process as the user could start your program from anywhere. Even if you think you always control the current working directory, you will be surprised how often you will be wrong.

Do you have a debugger? Why not insert a breakpoint and check the values used at each step?
If the file system says "cannot find file", I wouldn't bother arguing with it...

use \\ for the file path directory if it in local.. if your file exists in network path use \\\\(atfirst).. So that it look for network drive..
Thanks

It is necessary to embed all external files into the executable and change your code to work with these embedded files rather than to expect files on the disk.
To use images or whatever you need files("xml/txt/doc"), you need to set the build action of your file to Embedded Resource, and call the method with the fully qualified name of the file, where the name is assembled like this:
[RootNameSpaceOfTheProject].[NameOfFolderInTheProject].[FileNameWithExtension]
Example:
Call the method:
var b = ResourceOperations.GetResourceAsByteArray("Store.Resources.EmbeddedIcons.toolbox.png");
Now you can write the byte array to a temporary file for example and use this as an image source, or you can build an image from the byte array directly. At least, you've got your data...
and to save this files to a disk we should write a code by #Jon Skeet :
public static void CopyStream(Stream input, Stream output)
{
// Insert null checking here for production
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, bytesRead);
}
}
then call it:
using (Stream input = assembly.GetManifestResourceStream(resourceName))
using (Stream output = File.Create(path))
{
CopyStream(input, output);
}

Related

Issue in file access with absolute paths

I've created a .NetCore console application in which am trying to check if a file exists using its absolute path, but am facing issues, I always get a false response even though the file exists. Even though I pass absolute path as parameter to API, it always prefixes the current working directory, so the path gets evaluated as doesn't exists.
I'm running this code on a windows 10 desktop and the application is created using .NetCore 2.1. I've tried various different methods to evaluate the existence of file like FileInfo Class instance and File.Exists static method. They've failed so far. I've diagnosed the issue, but I couldn't find a way to fix it.
using System;
using System.IO;
namespace FileAccess
{
class Program
{
static void Main(string[] args)
{
FileInfo fileInfo = new FileInfo(#"‪D:\ScriptData\test.zip");
Console.WriteLine($"Full Name: {fileInfo.FullName}");
Console.WriteLine($"FileInfo.Exists: {fileInfo.Exists}");
Console.Write($"File.Exists with #: {File.Exists(#"‪D:\ScriptData\test.zip")}")
Console.ReadLine();
}
}
}
The output of the code is:
Full Name: D:\Work\Samples\FileAccess\FileAccess\bin\Debug\netcoreapp2.1\?D:\ScriptData\test.zip
False
False
Even though am passing the absolute path, it prefixes the current working directory to the path I've passed. I've checked the Access to the file, its all fine, still I get false as response for both the cases.
Screenshot of Error
Screenshot of Debug Info
Judging your screen shot and the output, there is an invisible character at the start of the file path. That will cause .NET not to recognize it is an absolute path and automatically it will make it an absolute path itself.
If you use this code, you will notice that the inserted ? causes the problem here:
System.IO.FileInfo fi = new System.IO.FileInfo(#"?D:\some_file.ext");
Which outputs: C:\Users\...\ConsoleApp8\bin\Debug\netcoreapp2.2\?D:\some_file.ext.
Instead of:
System.IO.FileInfo fi = new System.IO.FileInfo(#"D:\some_file.ext");
Which outputs: D:\some_file.ext.
If you put your code in a HEX editor, you will see there is indeed a character before D:.
Thank goodness you cut and paste your original code! I know you did because when I cut and paste your code I can see that you have invisible characters after the open quote and before the D:\.
These two lines look identical but they're not! Cut and paste them if you don't believe me!
Your code:
FileInfo fileInfo = new FileInfo(#"‪D:\ScriptData\test.zip");
Fixed code:
FileInfo fileInfo = new FileInfo(#"D:\ScriptData\test.zip");
Here's what the binary editor shows.
You've got E2 80 AA secretly stuck in your source code file at the beginning of your filename. Which happens to be the UTF-8 representation of the LEFT-TO-RIGHT EMBEDDING character.

Receiving IOException

I'm getting the IOException Error when I try this, and I'm not sure what I'm doing wrong:
This is my code:
FileStream fStream = new FileStream(PDFFilePath(), FileMode.CreateNew, FileAccess.ReadWrite);
Where
private string PDFFilePath()
{
m_sFilePath = "C:/Pictures/";
return m_sFilePath;
}
What am I missing?
I'm using this FileStream to save PDF documents using the Pdf.Select NuGet. It uses a method:
PdfDocument.Save(Stream stream);
I think you should be specifying your path this way:
private string PDFFilePath(string filename)
{
m_sFilePath = #"C:\Pictures\" + filename;
return m_sFilePath;
}
Like #Reisclef said, you have to provide a file path, not a directory. Since you're using FileMode.CreateNew, it has to be a new file, so you might also want to use File.Exists(m_sFilePath) before returning.
You have several problems here.
First, if you use a path like C:\Pictures\, it'll complain about the trailing \.
Secondly, you need to specify an actual file here, not just a directory. It makes no sense to just specify a directory (rather than a file) in this case - that's why it's called a File Stream and not a Directory Stream. I suggest using Path.Combine for this. Also, if you're just trying to move an already-existing file to this directory, you should do File.Move rather than using a FileStream.
Third, you only want to use FileMode.CreateNew if there's no possibility that the file already exists in the destination folder; if it does exist, this will throw an exception.
Fourth, it's a bad practice to hardcode paths like this. You usually want to get the path from a configuration file and make sure that the Pictures directory does, in fact, exist before you try to do this operation; otherwise it may fail when you deploy it to another machine.
Fifth, the PDFFilePath method seems rather pointless in this case - you can do the same thing with a string constant or creating a readonly string in the constructor.

Clarification on Build Action

I have a project that uses an Access DB file for reference tables. This is to be used at work, but I am developing it at home. Up until now, I've simply run the debugger in VS2010, then copied the relevant class files, exe, etc from the /bin folder to a flash drive, and it's worked fine. But with the DB added in, it suddenly crashes on launch.
I know the problem is the file location of the DB file. Originally the Build Action of the DB was sent to Content. I have changed it to Embedded Resource, which as far as I understand means it will be part of the exe file now.
Am I correct in this? If not, what option do I need to select to have the DB become just a compiled part of the exe, or one of the other dll's?
If the db file is embedded, you can't access it to add/removes rows etc.
Why did you change the build action to Embedded Resource ? It'll be better to put as Content, so the db is a separate file than the exe (but still in the same directory), and then build the path to the db file (i.e. using Application.StartupPath).
Anyway, if you want to set it as Embedded you'll need to extract the db at runtime and store it somewhere before using it.
Here is a method that can extract a file from the embedded resources (of course you'll need to change the filename, or pass it as argument):
private void ExtractFromAssembly()
{
string strPath = Application.LocalUserAppDataPath + "\\MyFile.db";
if (File.Exists(strPath)) return; // already exist, don't overwrite
Assembly assembly = Assembly.GetExecutingAssembly();
//In the next line you should provide NameSpace.FileName.Extension that you have embedded
var input = assembly.GetManifestResourceStream("MyFile.db");
var output = File.Open(strPath, FileMode.CreateNew);
CopyStream(input, output);
input.Dispose();
output.Dispose();
System.Diagnostics.Process.Start(strPath);
}
private void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
while (true)
{
int read = input.Read(buffer, 0, buffer.Length);
if (read <= 0)
return;
output.Write(buffer, 0, read);
}
}
The file will be copied in the local application path, in the user directory. It'll be done the first time the app is started, because otherwise the db file will be overwritten each time the application start (overwritten with the clean db package in the exe)

How to properly use File.Exists in windows application

I have a windows application with an "images" folder. I need to check if an image exists, which it will, during runtime. The below code is what I have but it always returns false.
if ( File.Exists("images/" + item.tool_image) )
{
Image img;
img = Image.FromFile("images/" + item.tool_image);
titem.Image = img;
}
Whats the problem or the proper way to do this.
If the file you're looking for doesn't exist in the working directory of your application, call File.Exists with a fully-qualified path:
if (File.Exists(#"C:\images\" + item.tool_image))
{ ... }
Of course, verify that a file actually exists at that location.
You'll find life easier if you use the tools provided by the Path class:
if (File.Exists(Path.Combine(#"C:\images", item.tool_image)))
{ ... }
The path is wrong try to change it to
string basePath = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
string imageFileName = System.IO.Path.Combine(basePath, "Images",item.tool_image);
if ( File.Exists(imageFileName) )
{
Image img;
img = Image.FromFile(imageFileName);
titem.Image = img;
}
How to properly use File.Exists in windows application?
You don't!
It's almost never appropriate to check if a file exists before trying to open. There are other things at work here: permissions, locking, sharing, time.
Instead, the correct way to do this is to try to open the file, whether it exists or not, and then catch the exception if your attempt to open the file fails. You have to be able to handle this exception anyway, even after performing the File.Exists() check. This makes your initial File.Exists() check not only redundant to your code, but wasteful, because it causes an extra trip out to the file system... and there's not much you can do in programming that's slower than going to the file system.
it is looking from the location where the code is currently running, also the '/' is the wrong direction. also, you are defining the path in multiple places, which can lead to problems later.
var path = string.Format(#"c:\somewhere\images\{0}", item.tool_image);
if (File.Exists(path))
{
Image img;
img = Image.FromFile(path);
titem.Image = img;
}
it's up to you to set the variable path , but in all likelihood, in your code example the location you expect isn't being checked.
The way you're calling it, you are looking for a file of whatever is in the string item.tool_image inside the images folder. Note that this images folder is located inside whatever directory contains your executable.
For instance, i just called File.Exists("images/image.jpg") and it worked.
As everyone has mentioned, use the fully qualified path. I also make heavy use of the Path.Combine, so I don't have to worry about missing a slash or two when I'm combining directories. The current executing directory is also useful...
File.Exists(Path.Combine(Environment.CurrentDirectory, "Images", item.tool_image));

How to open or run unknown file converted into byte[]

I use to store document/file in byte[] in database, and I want user can view/run that file from my application.
You need to know the file extension for the file you're writing, so the OS can run the default program based on the extension. The code would be something like this:
byte[] bytes = GetYourBytesFromDataBase();
string extension = GetYourFileExtension(); //.doc for example
string path = Path.GetTempFileName() + extension;
try
{
using(BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create)))
{
writer.Write(yourBytes);
}
// open it with default application based in the
// file extension
Process p = System.Diagnostics.Process.Start(path);
p.Wait();
}
finally
{
//clean the tmp file
File.Delete(path);
}
You will need to store the file extension in the database too. If you don't have the file extension the problem becomes very difficult as you cannot rely on the operating system to work out which program to launch to handle the file.
You can use the following pattern:
Load data from database and save to file using the original file extension.
Start a new System.Diagnostics.Process that points to the saved file path.
As you have saved the file with the original file extension, the OS will look for a program that is registered for the extension to open the file.
As chibacity and Daniel suggest, storing the file extension in the db, and agreed -- storing the file extension, or at least some indicator that tells you the file type, is a good idea.
If these files are of a format of your own creation then you might also want to store information about which version of the file format the data is stored in. During development file formats are prone to changing, and if you don't remember which version you used to store the data then you have a hard job recovering the information.
The same problems are faced in object persistence generally.

Categories

Resources