I am not new to C# but quite new to file handling. My current idea is to read files (of any kind, for example jpg, txt, pdf etc) to a buffer to be able to do something with it later, for example just write an exact copy to the same folder (for testing) or send it to another pc via network. I know that there is a specific method for sending files via network, but I'd like to be able to handle the file itself and understand how to open files the correct way and write them the correct way to have a working copy.
If I just open a file and use for example a StreamReader like this:
using (StreamReader sr = new StreamReader(sourcePath, GetEncoding(sourcePath)))
{
// Read the stream to a string, and write the string to the console.
String line = sr.ReadToEnd();
Console.WriteLine(line);
WriteFile(outputFile, GetEncoding(sourcePath), line);
}
it will create a bigger file (for example of an jpg) which does not work in the end. I think it has something to do with the encoding, but since I have to little knowledge about files itself maybe someone can give me some helpful tips.
Related
I'm working on an application plugin. The base software has an API method that requires as input the path of a file in the disk.
I am generating the files with my application but this file has to be read just once then deleted.
I'm saving the file to the disk, giving the path to the method and then deleting the file.
I would like to write to memory this file and use the API method using the path to this file. It would increase greatly performance help on other issues.
Is it possible?
I'm using .NET 4.7
Thank you!
Are you looking like this or something else?
string fileName = "<Your File name>";
int bufferSize = 1024;
using (var fileStream = File.Create(fileName, bufferSize, FileOptions.DeleteOnClose))
{
// now use that fileStream to write wour data and it will auto delete after file close
}
This will store file in disk and you ca use path and it will auto delete after file close.
The base software has an API method that requires as input the path of a file in the disk.
Do you control or can you change the base software method? if the input parameter type of method of base software is type string (which it sounds like but you have not shared any code) then there's no way to pass the memory stream to that method.
if you get response back from the method after processing is finished, i.e. the base method does not require file available on the disk afterward then you can create file on disk, pass file path to the method as input parameter and then delete the file after control returns
File.Create(filePath);
baseObj.BaseMethod(filePath);
File.Delete(filePath);
However, you should show some code to get more relevant suggestion.
I have read many other posts about this topic, but none appear to solve my problem directly (which surprises me).
Regardless...I wrote a log parser and very simply I am looking to copy a file from a remote machine locally, prior to parsing it. The file I am trying to copy is being written to constantly and I have ‘random’ success in copying it. Sometimes it will work and other times I will get an ‘access is denied’ or FileAccess error. A few other points:
Whenever I use windows explorer to copy the file locally, I never
have a problem copying it (which leads me to believe it’s perfectly
possible to copy the file 100% of the time).
I can always open the file using a text editor in its remove location.
I do not own the file being written to and do not wish to ‘lock’ it in anyway such that the application that is actually writing to this file fails.
Does anyone have any suggestions for how to copy this file?
The current command I am using is:
File.Copy(this.txt_log_file_to_analyze.Text, sLogFileToAnalyze,true);
I guess you'll have to open the file using:
File.Open(this.txt_log_file_to_analyze.Text,FileMode.Open,FileAccess.Read,FileShare.ReadWrite)
and then copy the contents of the file 'manually' i.e.
using (var from = File.Open("path", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var to = File.OpenWrite("to_path"))
{
from.CopyTo(to);
}
or if .NET 4.5 see How do I copy the contents of one stream to another?
Using the above api, you can specify that you do not want exclusive access to the file.
I want to be able to read any file into a string, for instance the way notepad might open a word file. Using the following code:
StreamReader sr = new StreamReader(filePath);
text += sr.ReadToEnd();
sr.Close();
works fine on a basic text file but when using it on say a word file I just get a few odd characters whereas opening the same file in notepad shows me the entire file, text, special characters etc. I'm using this as part of a file drop into a textbox. Basically I'm looking to get the same output you would get when you open any file in notepad. What should I be using instead?
Using your code from the original question and opening a file, does show the entire stream (when looking it in debugger) - The problem is that most of these binary files have null terminators (\0 char) which will cause most viewers to stop reading the contents of the stream.
If you remove/escape the '\0' you'll see the entire stream just like in notepad.
For example:
string filePath = #"c:\windows\system32\calc.exe";
StreamReader sr = new StreamReader(filePath);
string text = sr.ReadToEnd();
sr.Close();
textBox1.Text = text.Replace('\0', ' ');
Add a textbox1 to a form and see for yourself... You'll see the entire stream...
This should give you the functionality that you want. First read the file in as a byte[] using
byte[] data = File.ReadAllBytes(fileName);
then just encode it with ascii, or whatever.
string s = Encoding.ASCII.GetString(data);
I'm assuming you're referring to WordPad, which is also included with Windows, rather than Notepad. WordPad, in addition to showing basic text files, also knows to parse and edit Word files (.DOCX, but oddly enough not the older .DOC files), Rich Text Format files (.RTF), and OpenOffice documents (*.ODT). This doesn't come freely just by opening the Word file and displaying its content - there is a lot of code inside WordPad to parse this binary data and display it properly, not to mention the code to edit and save it again.
If you need to retrieve the data from Word files, there are several programmatic options, starting with automating the Word application itself using the Word APIs. However, this solution is problematic for running on a server, or if you need to open them where there is no Word installed.
In this case you also have several options. For post-2007 documents with the .DOCX extension, you can use the System.IO.Packaging namespace to open the DOCX and extract its relevant parts, but it's up to you to understand the syntax of the XML files within. Alternately, you can purchase a third-party library that does it for you, such as Aspose, which I've worked with and were fine. There are others out there too.
I am storing attachments in my applications.
These gets stored in SQL as varbinary types.
I then read them into byte[] object.
I now need to open these files but dont want to first write the files to disk and then open using Process.Start().
I would like to open using inmemory streams. Is there a way to to this in .net. Please note these files can be of any type
You can write all bytes to file without using Streams:
System.IO.File.WriteAllBytes(path, bytes);
And then just use
Process.Start(path);
Trying to open file from memory isn't worth the result. Really, you don't want to do it.
MemoryStream has a constructor that takes a Byte array.
So:
var bytes = GetBytesFromDatabase(); // assuming you can do that yourself
var stream = new MemoryStream(bytes);
// use the stream just like a FileStream
That should pretty much do the trick.
Edit: Aw, crap, I totally missed the Process.Start part. I'm rewriting...
Edit 2:
You cannot do what you want to do. You must execute a process from a file. You'll have to write to disk; alternatively, the answer to this question has a very complex suggestion that might work, but would probably not be worth the effort.
MemoryMappedFile?
http://msdn.microsoft.com/en-us/library/system.io.memorymappedfiles.memorymappedfile.aspx
My only issue with this was that I will have to make sure the user has write access to the path where I will place the file...
You should be able to guarantee that the return of Path.GetTempFileName is something to which your user has access.
...and also am not sure how I will detect that the user has closed the file so I can delete the file from disk.
If you start the process with Process.Start(...), shouldn't you be able to monitor for when the process terminates?
If you absolutely don't want to write to disk yourself you can implement local HTTP server and serve attachemnts over HTTP (like http://localhost:3456/myrecord123/attachment1234.pdf).
Also I'm not sure if you get enough benefits doing such non-trivial work. You'll open files from local security zone that is slightly better then opening from disk... and no need to write to disk yourself. And you'll likely get somewhat reasonable warning if you have .exe file as attachment.
On tracking "process done with the attachment" you more or less out of luck: only in some cases the process that started openeing the file is the one that is actually using it. I.e. Office applications are usually one-instance applications, and as result document will be open in first instance of the application, not the one you've started.
I have a portable executable that saves data to a file in the same folder as the executable. Is there any way that I can save data into the executable itself when I close the app?
This maybe weird, but taking the data with me and only have one file for the exe and data would be great.
Would prefer if this was made with C#, but is not a requisite.
You cannot modify your own EXE to contain stored data in anything approaching an elegant or compact way. First off, the OS obtains a lock on the EXE file while the application contained within is being run. Second, an EXE comes pre-compiled (into MSIL at least), and modification of the file's source data usually requires recompilation to reset various pointers to code handles, or else a SERIOUS knowledge on a very esoteric level about what you're doing to the file.
The generally-accepted methods are the application config file, a resource file, or some custom file you create/read/modify at runtime, like you're doing now. Two files for an application should not be cause for concern
You can, by reserving space through the means of using a string resource and pad it out. You need to do a bit of detective work to find out exactly where in the offset to the executable you wish to dump the data into, but be careful, the file will be "in use", so proceed cautiously with that.
So right now you're using an app.config (and Settings.settings) file?
I believe this is the most compact way to save data close to the .exe.
I would highly doubt you can alter the manifest of the .exe, or any other part of it.
Edit: Apparently, there might be some ways after all: http://www.codeproject.com/KB/msil/reflexil.aspx
There is one way using multiple streams, but only works in NTFS filesystems.
NTFS allows you to define alternative "named" streams in one file. The usual content is in the main = unnamed stream. It has something to do with the extra info you can see when you right click a file and check properties.
Unfortunatly C# has no support for multiple streams, but there are open source pojects that can help you.
See this link for a nice wrapper to read and write multiple streams to one single file in C#
Alternate data streams might work. By using the ::stream syntax you can create a data stream within your exe and read/write data.
Edit:
to create/access an alternate data stream, you will use a different filename. Something like:
applicAtion.exe:settings:$data
this will access a data stream named "settings" within application.exe. To do this you need to add the :settings:$data to the filename when reading or writing to the file. This functionality is provided by ntfs so it shold work in c# and should work when the application is running.
Additional information is available at: http://msdn.microsoft.com/en-us/library/aa364404(VS.85).aspx
If you want to take the data with you and only have one file for the exe and data, .zip them into a self-extracting .exe.
you can add data to end of executable file :
var executableName = Process.GetCurrentProcess().MainModule.FileName;
// rename executable file
var newExecutableName = fullPath.Replace(".exe", "_.exe");
FileInfo fi = new FileInfo(executableName);
fi.MoveTo(newExecutableName);
// make copy of executable file to original name
File.Copy(newExecutableName, executableName);
// write data end of new file
var bytes = Encoding.ASCII.GetBytes("new data...");
using (FileStream file = File.OpenWrite(executableName))
{
file.Seek(0, SeekOrigin.End);
file.Write(bytes, 0, bytes.Length);
}
// we can delete old file when exited