Is there a way to calculate the checksum of a file that is readonly?
The only examples I have seen uses an algorithm like this
public string GetChecksum()
{
FileStream file = new FileStream(_filePath, FileMode.Open);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] retVal = md5.ComputeHash(file);
file.Close();
StringBuilder sb = new StringBuilder();
foreach (byte t in retVal)
{
sb.Append(retVal[1].ToString("x2"));
}
return sb.ToString();
}
You can open a file even if it's readonly.
It is not possible to generate a checksum without opening the file, since you can't read a file without opening it.
You should pass FileAccess.Read to open it as read-only.
Also, you should generate checksums using SHA512, not MD5.
According to the documentation, the FileStream constructor you are using opens the file for read/write. Use an overload that specifies FileAccess.Read.
The constructor is given read/write
access to the file, and it is opened
sharing Read access
You cannot generate a checksum without reading the entire file.
Generally, readonly files can be opened. There might be file or folder permissions that prevent a given user from opening the file.
Well, no. You have to read a file to do anything with what's in it. But you're opening with Generic access when you probably want FileStream(_filePath,FileAccess.Read,true,4096,true); to open it read-only. StreamReader will do this automatically.
Related
This is a question which was asked to me in an interview and still could not find a way to do it-
Suppose I have a .txt file and I want to delete the last 4 characters from the content of that file without opening the file. The first question is- Is it really doable? If yes, what is the way to do it?
I guess you can't read the content of the file. So if you can "open" it with write only access you could do:
using (var fileStream = File.Open("initDoc.txt", FileMode.Open, FileAccess.Write))
{
fileStream.SetLength(fileStream.Length - 4);
}
Of course you would need additional checks to make sure you are subtracting the correct number of bytes depending on the encoding, not subtracting more than the length etc.
If you can't use FileMode.Open, you can use an overload of the FileStream constructor that uses a SafeFileHandle. To acquire a SafeFileHandle to a file, you need to use C# Interop. In this example below i have wrapped the interop code to get a file handle in a class called "UnmanagedFileLoader":
var unmanagedFileLoader = new UnmanagedFileLoader("initDoc.txt");
using (var fileStream = new FileStream(unmanagedFileLoader.Handle, FileAccess.Write))
{
fileStream.SetLength(fileStream.Length - 4);
}
The UnmanagedFileLoader internally uses the unmanaged CreateFile function to open an existing file with write permissions:
handleValue = CreateFile(Path, GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
For more info how to acquire a SafeFileHandle you can check out this link:
http://msdn.microsoft.com/en-us/library/microsoft.win32.safehandles.safefilehandle%28v=vs.110%29.aspx
If you want to skip the FileStream ways, the third way to do it would be to use StreamReader and StreamWriter, and then read a file with StreamReader without the last 4 bytes, and then write it using a StreamWriter. But i would still recommend using the FileStream examples above.
EDIT: I assume "opening the file" means "getting a handle to the file".
Sure it's possible :
Open a handle to the drive that contains the file
Get the file system type
Scan the content of the structure that contains information about all files: the MFT (for NTFS), the FAT records..etc.
Find the entry that corresponds to your file
Updates the entry (write) by subtracting 4 to the value that stores the "file size" information :)
If your concern is about reading all the data for a long file: that isn't necessary. If we assume you really do mean bytes, simply:
using (var file = File.Open(path, FileMode.Open, FileAccess.Write)) {
file.SetLength(file.Length - 4);
}
this does not read the contents of the file.
If you mean characters, then you need to think very carefully about the encoding - 4 characters is not necessarily 4 bytes.
I'm having trouble copying a file and then verifying the integrity of the file afterward. I've tried every file copying method I can think of (File.Copy, filestreams, trying to do a binary copy) but the file hash is always different after the copy. I've been searching around and I notice a lot of people saying that copying a file from a network share can cause this but I get the same results from shares as I do just straight from my hard drive.
//File hashing method:
private byte[] hashFile(string file)
{
try
{
byte[] sourceFile = ASCIIEncoding.ASCII.GetBytes(file);
byte[] hash = new MD5CryptoServiceProvider().ComputeHash(sourceFile);
return hash;
...
Using this method the origional file and the copied file always produce the same hash (individually) through every run but the two hashes are not the same. Does anyone know of a way to copy files without changing the file hash?
I Think you are Hashing the FileName .. and not Content !
so sure it wont compute as same!
check the Value and Length of file and byte[] sourceFile
It seems you are passing the filename instead of the file contents to the hash function.
Use something like this:
byte[] hash = md5.ComputeHash(File.ReadAllBytes(filename));
Or this:
using (var stream = File.Open(filename)) {
byte[] hash = md5.ComputeHash(stream);
}
I want to prompt a user to save a file when some modification has been done to it but the problem is i can't for the life of me do that.
Some people have suggested using FileInfo class but it only gives you the lastWriteTime, LastAccessTime and CreationTime.
I would like to use FileInfo class rather than FileSystemWatcher to check for modifications but how?
Example: Say a user has edited a file, within my program, that they loaded and clicks EXIT, i want a way to check whether any modifications were done on the file. If none, exit. If some, prompt user to save the file. So how do i check for modifications on that FILE?
The easiest way is to calculate the MD5 hash of the file and compare to the original MD5 hash and if these two don't match the file was modified...
using (var md5 = new MD5CryptoServiceProvider())
{
var buffer = md5.ComputeHash(File.ReadAllBytes(filename));
var sb = new StringBuilder();
for (var i = 0; i < buffer.Length; i++)
{
sb.Append(buffer[i].ToString("x2"));
}
return sb.ToString();
}
Here are some examples of how to use the File or FileInfo class to get the LastWriteTime.
http://www.csharp-examples.net/file-creation-modification-time/
I would store the timestamp of the file when you load it, then compare it to the File.GetLastWriteTime() to see if the file has been saved since then. If the file was modified by an outside source, you can give the user the option to discard their changes and reload the file, or save their changes to a new file.
How can I read content of a text file inside a zip archive?
For example I have an archive qwe.zip, and insite it there's a file asd.txt, so how can I read contents of that file?
Is it possible to do without extracting the whole archive? Because it need to be done quick, when user clicks a item in a list, to show description of the archive (it needed for plugin system for another program). So extracting a whole archive isn't the best solution... because it might be few Mb, which will take at least few seconds or even more to extract... while only that single file need to be read.
You could use a library such as SharpZipLib or DotNetZip to unzip the file and fetch the contents of individual files contained inside. This operation could be performed in-memory and you don't need to store the files into a temporary folder.
Unzip to a temp-folder take the file and delete the temp-data
public static void Decompress(string outputDirectory, string zipFile)
{
try
{
if (!File.Exists(zipFile))
throw new FileNotFoundException("Zip file not found.", zipFile);
Package zipPackage = ZipPackage.Open(zipFile, FileMode.Open, FileAccess.Read);
foreach (PackagePart part in zipPackage.GetParts())
{
string targetFile = outputDirectory + "\\" + part.Uri.ToString().TrimStart('/');
using (Stream streamSource = part.GetStream(FileMode.Open, FileAccess.Read))
{
using (Stream streamDestination = File.OpenWrite(targetFile))
{
Byte[] arrBuffer = new byte[10000];
int iRead = streamSource.Read(arrBuffer, 0, arrBuffer.Length);
while (iRead > 0)
{
streamDestination.Write(arrBuffer, 0, iRead);
iRead = streamSource.Read(arrBuffer, 0, arrBuffer.Length);
}
}
}
}
}
catch (Exception)
{
throw;
}
}
Although late in the game and the question is already answered, in hope that this still might be useful for others who find this thread, I would like to add another solution.
Just today I encountered a similar problem when I wanted to check the contents of a ZIP file with C#. Other than NewProger I cannot use a third party library and need to stay within the out-of-the-box .NET classes.
You can use the System.IO.Packaging namespace and use the ZipPackage class. If it is not already included in the assembly, you need to add a reference to WindowsBase.dll.
It seems, however, that this class does not always work with every Zip file. Calling GetParts() may return an empty list although in the QuickWatch window you can find a property called _zipArchive that contains the correct contents.
If this is the case for you, you can use Reflection to get the contents of it.
On geissingert.com you can find a blog article ("Getting a list of files from a ZipPackage") that gives a coding example for this.
SharpZipLib or DotNetZip may still need to get/read the whole .zip file to unzip a file. Actually, there is still method could make you just extract special file from the .zip file without reading the entire .zip file but just reading small segment.
I needed to have insights into Excel files, I did it like so:
using (var zip = ZipFile.Open("ExcelWorkbookWithMacros.xlsm", ZipArchiveMode.Update))
{
var entry = zip.GetEntry("xl/_rels/workbook.xml.rels");
if (entry != null)
{
var tempFile = Path.GetTempFileName();
entry.ExtractToFile(tempFile, true);
var content = File.ReadAllText(tempFile);
[...]
}
}
I've been playing around with encrypting and decrypting files in VC# Express 2010.
All the tutorials and documentation I've seen require two FileStreams in order to encrypt the file - one for reading the unencrypted version, and the other for encrypting. When I actually wrote the code it kept throwing an error telling me it could not open the file because it was opened by another process at the output filestream.
I'm assuming that's because the file is opened by the input filestream. So that means I have to specify a different filename? So even after the operation is successful I'll now have the original unencrypted file in the directory and a separate encrypted version? Doesn't that defeat the point? Or am I doing something wrong here? My code is similar to this...
public string filename = "test.xml";
using (FileStream input = new FileStream(filename, FileMode.Open, FileAccess.Read))
using (FileStream output = new FileStram(filename, FileMode.Open, FileAccess.Write))
using (....all the crypto stream and transform stuff...)
{
...do the encryption....
}
You're right but it's not defeating the point. The (streaming) crypto APIs are intended to encrypt from Src to Dst. Think encrypting output while sending/receiving over a network etc. This keeps them simple, as they should be.
You complicate the issue by using the same file for Src and Dst. That is not totally impossible but like Copying a File over itself it needs some extra care.
Consider that in general, encrypting will increase the File size. So it is not safe to Encrypt a file in place. Decrypting might be, but I wouldn't risk it.
What you need is a Temp file and a rename action after completion.
In your example, you can't create a separate filestream for both input and output on the same file, but you can create a handle that will read and write. The FileAccess enum has the flags attribute, so you'd just say var handle = new FileStream(filename, FileAccess.Read | FileAccess.Write); The obvious downside to this is you are going to have data lost if your encryption doesn't complete successfully.
I recommend having a separate file for the output though, atleast that way you won't lose data if your program breaks unexpectedly. If the encryption completes successfully, then delete the original and rename the encrypted file with the original file name.
Use File.ReadAllBytes. Then those bytes post to your encryptor, must work.
There is another parameter where you can specify whether or not to allow another process to read or write to the file.
openFile is a string that represents the file name.
using (FileStream fileIn = new FileStream(openFile, FileMode.Open, FileAccess.Read, FileShare.Write))
using (FileStream fileOut = new FileStream(openFile, FileMode.Open, FileAccess.Write, FileShare.Open))
This way, you can read and write to the same file.
while (myfileStream.Position < fileLength)
{
fileIn.Read(buffer, 0, 51200);
buffer = encrypt(buffer);
fileOut.Write(buffer, 0, 51200);
}
While this is easy and you don't have to write to a temporary file or have to move/rename etc, this can be really dangerous because if the encryption breaks suddenly for some reason, you will lose data!
Also, the encrypt function is something I implemented. AesCryptoServiceProvider along with CryptoStream can be used :)