I am developing an application where from several screens user has to download a sample file(excel) to work with. What will be the preferable way to do so.
What i am doing is
Placing the file in the directory where application is executing and download the files using Application.StartupPath. This does not sounds like a very good solution. As at anytime user could edit the files or delete the files or such things.
What i want to do is
I want to add all the files in my resources and download files from the resources. I add the files but i need a little help on how to download it from resources.
Thanks
you can use:
class ResourceHelper
{
public static void MakeFileOutOfAStream(string stream, string filePath)
{
using(var fs = new FileStream(filePath,FileMode.Create,FileAccess.ReadWrite))
{
CopyStream(GetStream(stream), fs);
}
}
static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, read);
}
}
static Stream GetStream(string stream)
{
return Assembly.GetExecutingAssembly().GetManifestResourceStream(stream));
}
}
and with stream pass the complete name of you resource, that is the namespace + the resource file name ( evantual folder are to be considered as namespace part ) case sensitive. Remember to flag the file in your project as embedded resource.
You can use Assembly.GetManifestResourceStream and save the stream in some file to work with it.
Here is a simple example:
using (var resource = Assembly.GetManifestResourceStream("resource_key"))
using (var file = File.OpenWrite(filename))
{
var buffer = new byte[1024];
int len;
while ((len = resource.Read(buffer, 0, buffer.Length)) > 0)
{
file.Write(buffer, 0, len);
}
}
Please note. There is no way to store the file changes back to the resources.
Related
I need to change a file's encoding. The method that I've used loads all the file in memory:
string DestinationString = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes(File.ReadAllText(FileName)));
File.WriteAllText(FileName, DestinationString, new System.Text.ASCIIEncoding());
This works for smaller files (in case that I want to change the file's encoding to ASCII), but it won't be ok with files larger than 2 GB. How to change the encoding without loading all the file's content in memory?
You can't do so by writing to the same file - but you can easily do it to a different file, just by reading a chunk of characters at a time in one encoding and writing each chunk in the target encoding.
public void RewriteFile(string source, Encoding sourceEncoding,
string destination, Encoding destinationEncoding)
{
using (var reader = File.OpenText(source, sourceEncoding))
{
using (var writer = File.CreateText(destination, destinationEncoding))
{
char[] buffer = new char[16384];
int charsRead;
while ((charsRead = reader.Read(buffer, 0, buffer.Length)) > 0)
{
writer.Write(buffer, 0, charsRead);
}
}
}
}
You could always end up with the original filename via renaming, of course.
I m developing an application that reads files from a remote server and copies it onto the local drive.
The code I m using to read and write the file is -
string saveTo1 = savePath + #"\" + filename[i];
byte[] buffer = new byte[32768];
using (Stream input = getResponse.GetResponseStream())
{
using (FileStream output = new FileStream(saveTo1, FileMode.OpenOrCreate))
{
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, bytesRead);
}
output.Close();
}
}
How can I create a log file that keeps track of the details of file copy and also records if there is any error while copying the files?
Thanks in advance :)
You can log in different ways.
EventLogger (as already suggested)
Custom file log (as already
answered)
Log Engine: I suggest you
log4net. It's very powerfull
and highly customizable.
Any way, I would shape the code in this way, where MyLogManager implement one of the previous solutions:
string saveTo1 = savePath + #"\" + filename[i];
byte[] buffer = new byte[32768];
try
{
using (Stream input = getResponse.GetResponseStream())
{
using (FileStream output = new FileStream(saveTo1, FileMode.OpenOrCreate))
{
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, bytesRead);
}
output.Close();
}
}
//logging good news and info
MyLogManager("Good news", FileDetails);
}
catch(Exception ex)
{
//logging bad news and exceptions info
MyLogManager("Bad news", ExceptionDetails);
}
Yes it is perfectly possible. Just create a file using the system.io file operations and for each file copied you open the log file and add a line. If you have an exception then rather than throwing it and breaking the application you can simply copy the exception details to the log file.
I would prefer to use this approach as you can tailor it to do exactly what you want.
there are so many logging framework available on the net. I would suggest NLog. Download and include it in ur Project.
You can do the following method,
try
{
//Write your code here
//OnSuccess : NLogger.Debug("file copied")
}
catch(Exception)
{
NLogger.Error("Exception Details");
}
There are advantages using NLog which takes care of Archival, File handles, etc.
What you are desiring is a simple log. You can make it more useful.
Check here:
.NET Logging Tools and Libraries
Please suggest me a good method that can be used to write a stream into a file.
I just need a simple c# function that can take a stream as input and do the job..
I need to do this for very large files ie files > 4GB.
Can this be done better using linq,extension methods etc?
Please provide me a good utility function that can also return the progress in percentage through yield.
Edit: I know about looping through a byte[] and writing it to a file. I've tried File.WriteAllBytes method. But,I'm just looking for a very nice way of doing it using linq,yield and extension methods.
Edit: Here is a utility function that should do the trick:
Update: Changed second parameter to file name
public delegate void ProgressCallback(long position, long total);
public void Copy(Stream inputStream, string outputFile, ProgressCallback progressCallback)
{
using (var outputStream = File.OpenWrite(outputFile))
{
const int bufferSize = 4096;
while (inputStream.Position < inputStream.Length)
{
byte[] data = new byte[bufferSize];
int amountRead = inputStream.Read(data, 0, bufferSize);
outputStream.Write(data, 0, amountRead);
if (progressCallback != null)
progressCallback(inputStream.Position, inputStream.Length);
}
outputStream.Flush();
}
}
I have over 125 TSV files of ~100Mb each that I want to merge. The merge operation is allowed destroy the 125 files, but not the data. What matter is that a the end, I end up with a big file of the content of all the files one after the other (no specific order).
Is there an efficient way to do that? I was wondering if Windows provides an API to simply make a big "Union" of all those files? Otherwise, I will have to read all the files and write a big one.
Thanks!
So "merging" is really just writing the files one after the other? That's pretty straightforward - just open one output stream, and then repeatedly open an input stream, copy the data, close. For example:
static void ConcatenateFiles(string outputFile, params string[] inputFiles)
{
using (Stream output = File.OpenWrite(outputFile))
{
foreach (string inputFile in inputFiles)
{
using (Stream input = File.OpenRead(inputFile))
{
input.CopyTo(output);
}
}
}
}
That's using the Stream.CopyTo method which is new in .NET 4. If you're not using .NET 4, another helper method would come in handy:
private static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, bytesRead);
}
}
There's nothing that I'm aware of that is more efficient than this... but importantly, this won't take up much memory on your system at all. It's not like it's repeatedly reading the whole file into memory then writing it all out again.
EDIT: As pointed out in the comments, there are ways you can fiddle with file options to potentially make it slightly more efficient in terms of what the file system does with the data. But fundamentally you're going to be reading the data and writing it, a buffer at a time, either way.
Do it from the command line:
copy 1.txt+2.txt+3.txt combined.txt
or
copy *.txt combined.txt
Do you mean with merge that you want to decide with some custom logic what lines go where? Or do you mean that you mainly want to concatenate the files into one big one?
In the case of the latter, it is possible that you don't need to do this programmatically at all, just generate one batch file with this (/b is for binary, remove if not needed):
copy /b "file 1.tsv" + "file 2.tsv" "destination file.tsv"
Using C#, I'd take the following approach. Write a simple function that copies two streams:
void CopyStreamToStream(Stream dest, Stream src)
{
int bytesRead;
// experiment with the best buffer size, often 65536 is very performant
byte[] buffer = new byte[GOOD_BUFFER_SIZE];
// copy everything
while((bytesRead = src.Read(buffer, 0, buffer.Length)) > 0)
{
dest.Write(buffer, 0, bytesRead);
}
}
// then use as follows (do in a loop, don't forget to use using-blocks)
CopStreamtoStream(yourOutputStream, yourInputStream);
Using a folder of 100MB text files totalling ~12GB, I found that a small time saving could be made over the accepted answer by using File.ReadAllBytes and then writing that out to the stream.
[Test]
public void RaceFileMerges()
{
var inputFilesPath = #"D:\InputFiles";
var inputFiles = Directory.EnumerateFiles(inputFilesPath).ToArray();
var sw = new Stopwatch();
sw.Start();
ConcatenateFilesUsingReadAllBytes(#"D:\ReadAllBytesResult", inputFiles);
Console.WriteLine($"ReadAllBytes method in {sw.Elapsed}");
sw.Reset();
sw.Start();
ConcatenateFiles(#"D:\CopyToResult", inputFiles);
Console.WriteLine($"CopyTo method in {sw.Elapsed}");
}
private static void ConcatenateFiles(string outputFile, params string[] inputFiles)
{
using (var output = File.OpenWrite(outputFile))
{
foreach (var inputFile in inputFiles)
{
using (var input = File.OpenRead(inputFile))
{
input.CopyTo(output);
}
}
}
}
private static void ConcatenateFilesUsingReadAllBytes(string outputFile, params string[] inputFiles)
{
using (var stream = File.OpenWrite(outputFile))
{
foreach (var inputFile in inputFiles)
{
var currentBytes = File.ReadAllBytes(inputFile);
stream.Write(currentBytes, 0, currentBytes.Length);
}
}
}
ReadAllBytes method in 00:01:22.2753300
CopyTo method in 00:01:30.3122215
I repeated this a number of times with similar results.
I have to pass the path of a config file to a framework method (Gurok SmartInspect). The config file is an embedded resource of the assembly. Currently I read the file from the assembly and store it outside and then pass the pathName. Is there a better / less complicated way to achieve this goal, without copying the file?
private static void ConfigLogger()
{
const string embeddedFileName = "xxx.SmartInspect.properties";
const string configFileName = "SmartInspect.properties";
ExtractFileFromAssembly(embeddedFileName, configFileName);
SiAuto.Si.LoadConfiguration(configFileName);
}
private static void ExtractFileFromAssembly(string assemblyFileName, string configFileName)
{
using (Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream(assemblyFileName) )
{
byte[] buffer = new byte[s.Length];
int read = s.Read(buffer, 0, (int)s.Length);
using (FileStream fs = new FileStream(configFileName, FileMode.Create))
{
fs.Write(buffer, 0, buffer.Length);
}
}
}
If the only way that Gurok SmartInspect reads configuration information is from a file that you pass it a path to and you've decided to embed that file in your assembly, then yes, your method is fine. You might want to consider adding some exception handling but otherwise I see no problem with this.