I need to store a byte[] in memory. I need to access it later. The byte[] represents a video. The following code will allow the file to be written to memory, as well as accessed from memory. When the remove method shown below is called, it can still be accessed later.
I have checked that the pathname is the same.
public void StoreVideo(byte[] video, string filename)
{
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var directoryname = Path.Combine(documents, "Videos");
Directory.CreateDirectory(directoryname);
var path = Path.Combine(directoryname, filename);
File.WriteAllBytes(path, video);
}
public void RemoveVideo(string filename)
{
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var directoryname = Path.Combine(documents, "Videos");
var path = Path.Combine(directoryname, filename);
File.Delete(filename);
}
public byte[] GetVideo(string filename)
{
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var directoryname = Path.Combine(documents, "Videos");
var path = Path.Combine(directoryname, filename);
if(File.Exists(path))
{
return File.ReadAllBytes(path);
}
return null;
}
The answer to this was just a small brain fart on the path being passed to the File.Delete method. However for those who run into this you should be aware that File.Delete DOES NOT throw any exception if it cannot delete the file. It should be good practice to wrap the File.Delete method a check for File.Exists
Related
I'm working on a website where users could apply to a certain job online.
A user must submit information in addition to a CV.
I'm new to this kind of work I would appreciate any kind of help.
Here is my attempt for the post method, but it generates the following exception:
Unexpected end of stream. Is there an end boundary?
public async Task<IHttpActionResult> PostCV()
{
IList<string> AllowedFileExtensions = new List<string> { ".txt", ".pdf" };
var parser = new MultipartFormDataParser(await Request.Content.ReadAsStreamAsync());
IList<FilePart> files = parser.Files;
IList<ParameterPart> formData = parser.Parameters;
FilePart uploadedContent = files.First();
var originalContentFileName =
uploadedContent.FileName.Trim('\"');
var originalExtension = Path.GetExtension(originalContentFileName);
if (!AllowedFileExtensions.Contains(originalExtension))
return BadRequest("Bad extension");
string modifiedContentFileName =
string.Format("{0}{1}", Guid.NewGuid().ToString(),
originalExtension);
Stream input = uploadedContent.Data;
string Url = string.Empty;
string fileName = string.Empty;
string directoryName = string.Empty;
directoryName = Path.Combine(HttpRuntime.AppDomainAppPath, "Uploads");
fileName = Path.Combine(directoryName, modifiedContentFileName);
if (File.Exists(fileName))
File.Delete(fileName);
using (Stream file = File.OpenWrite(fileName))
{
try
{
input.CopyTo(file);
file.Close();
var cv = new CV{ Path = fileName };
db.CVs.Add(cv);
db.SaveChanges();
return Json(cv);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
}
Thanks in advance
Apparently I should have chosen form-data in the body section, set the key with anything (e.g filename) and in the value choose file.
Also you need to create a folder in your path, in my case called Uploads in the directory specified.
Lots of thanks for those who helped.
I have my Info.plist file setup to handle the file type I want. When I download the file in Safari, and pick my App from the Open In, the file does get sent to my app and the OpenUrl function is called. In the Simulator, I am able to open the file using FileStream and process it without any problem. On the real device, I get an error that says something like:
Accesss to the path "/private/var/mobile/Containers/Data/Application/{KEY}/Documents/Inbox/file.ext is denied.
Here is my OpenUrl function:
public override bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
{
try
{
System.Console.WriteLine("OpenURL");
var fileName = url.AbsoluteUrl.LastPathComponent;
var newPath = Path.Combine(bookStorage, fileName);
var input = new System.IO.FileStream(url.Path, FileMode.Open);
var output = new System.IO.FileStream(newPath, FileMode.Create);
input.CopyTo(output);
output.Close();
input.Close();
var epub = new EpubParser(bookStorage, fileName);
var publication = new Publication(epub.getTitle(), fileName);
var id = epub.getId();
if (id != null)
{
publication.Id = id;
}
publication.Picture = epub.getImage();
var publications = new Publications();
publications.AddPublication(publication);
return true;
}
catch (Exception e)
{
var navController = (UINavigationController)this.Window.RootViewController;
var controller = navController.ViewControllers[0];
AlertView.Show(e.Message, controller);
return false;
}
}
Basically all I wanted was to copy the file to another location to keep it stored. So I used File.Copy instead and it worked! Apparently FileStream even with just the Open permissions set, still requires some type of write access to the folder.
var fileName = url.AbsoluteUrl.LastPathComponent;
var newPath = Path.Combine(bookStorage, fileName);
File.Copy(url.Path, newPath);
I am trying to decrypt .pgp files from a location and then moving those files to another location. I looked into this article and code accordingly. In my code I am developing an application which will check to a certain location after every 100 seconds and if there are files then it will decrypt and move. but I am getting this exception The process cannot access the file 'c:\file.pgp' because it is being used by another process.
Here is my code where I am calling that class which I copied from that article.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
//Do the stuff you want to be done every hour;
string sourcePath = #"files location";
string archivePath = #"move original file after decrypting location";
string targetPath = #"decrypted file location";
string pubkeyPath = #"public key location\PGPPublicKey.txt";
string privkeyPath = #"private key location\PGPPrivateKey.txt";
string fileName = "";
string destFile = "";
if (System.IO.Directory.Exists(sourcePath))
{
string[] files = System.IO.Directory.GetFiles(sourcePath);
// Copy the files and overwrite destination files if they already exist.
foreach (string s in files)
{
PGPDecrypt test = new PGPDecrypt(s,
privkeyPath,
"password",
targetPath + "decrypted.txt",
pubkeyPath);
FileStream fs = File.Open(s, FileMode.Open);
test.decrypt(fs, targetPath + "decrypted.txt");
// Use static Path methods to extract only the file name from the path.
fileName = System.IO.Path.GetFileName(s);
destFile = System.IO.Path.Combine(archivePath, fileName);
System.IO.File.Move(s, archivePath);
}
}
}
Where are you getting the error. If you are getting error while moving it might be because your filestream is not close. After decryption and before move close the filestream with fs.Close();
I believe the issue you are having is caused by the file not being closed, when you loop with the foreach loop the first iteration probably works. However, the next time, because it was never closed, it is still being used.
Try adding
fs.Close();
At the end of the foreach loop
This is I ended up and it is working
//Decrypt
using DidiSoft.Pgp;
PGPLib pgp = new PGPLib();
string inputFileLocation = file Location;
string privateKeyLocation = #"I posted my private at this location";
string privateKeyPassword = "Decryption Password";
string outputFile = #"Output Location";
// decrypt and obtain the original file name
// of the decrypted file
string originalFileName =
pgp.DecryptFile(inputFileLocation,
privateKeyLocation,
privateKeyPassword,
outputFile);
//Move decrypted file to archive
string path = Decrypted file Location;
string path2 = #"Archive file location" + Path.GetFileName(file); ;
try
{
if (!File.Exists(path))
{
// This statement ensures that the file is created,
// but the handle is not kept.
using (FileStream fs = File.Create(path)) { }
}
// Ensure that the target does not exist.
if (File.Exists(path2))
File.Delete(path2);
// Move the file.
File.Move(path, path2);
}
catch (Exception e)
{
}
Is there no .NET library call for copying a file to a directory? All library calls I found (e.g. File.Copy() or FileInfo.CopyTo()) do only support copying a file to another fully specified file.
string file = "C:\Dir\ect\ory\file.txt";
string dir = "C:\Other\Directory";
File.Copy(file, dir); // does not work, requires filename
Is there a library call? If no, what's the best way to write my own utility, do I really have to use Path.GetFileName()?
do I really have to use Path.GetFileName()?
Exactly:
string destination = Path.Combine(dir, Path.GetFileName(file));
Directory.CreateDirectory(dir);
File.Copy(file, destination);
Try this example
public class SimpleFileCopy
{
static void Main()
{
string fileName = "test.txt";
string sourcePath = #"C:\Users\Public\TestFolder";
string targetPath = #"C:\Users\Public\TestFolder\SubDir";
string sourceFile = System.IO.Path.Combine(sourcePath, fileName);
string destFile = System.IO.Path.Combine(targetPath, fileName);
System.IO.File.Copy(sourceFile, destFile, true);
}
}
I've had it suggested to me that I should use FileResult to allow users to download files from my Asp.Net MVC application. But the only examples of this I can find always has to do with image files (specifying content type image/jpeg).
But what if I can't know the file type? I want users to be able to download pretty much any file from the filearea of my site.
I had read one method of doing this (see a previous post for the code), that actually works fine, except for one thing: the name of the file that comes up in the Save As dialog is concatenated from the file path with underscores (folder_folder_file.ext). Also, it seems people think I should return a FileResult instead of using this custom class that I had found BinaryContentResult.
Anyone know the "correct" way of doing such a download in MVC?
EDIT:
I got the answer (below), but just thought I should post the full working code if someone else is interested:
public ActionResult Download(string filePath, string fileName)
{
string fullName = Path.Combine(GetBaseDir(), filePath, fileName);
byte[] fileBytes = GetFile(fullName);
return File(
fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}
byte[] GetFile(string s)
{
System.IO.FileStream fs = System.IO.File.OpenRead(s);
byte[] data = new byte[fs.Length];
int br = fs.Read(data, 0, data.Length);
if (br != fs.Length)
throw new System.IO.IOException(s);
return data;
}
You can just specify the generic octet-stream MIME type:
public FileResult Download()
{
byte[] fileBytes = System.IO.File.ReadAllBytes(#"c:\folder\myfile.ext");
string fileName = "myfile.ext";
return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}
The MVC framework supports this natively. The System.Web.MVC.Controller.File controller provides methods to return a file by name/stream/array.
For example using a virtual path to the file you could do the following.
return File(virtualFilePath, System.Net.Mime.MediaTypeNames.Application.Octet, Path.GetFileName(virtualFilePath));
If you're using .NET Framework 4.5 then you use use the MimeMapping.GetMimeMapping(string FileName) to get the MIME-Type for your file. This is how I've used it in my action.
return File(Path.Combine(#"c:\path", fileFromDB.FileNameOnDisk), MimeMapping.GetMimeMapping(fileFromDB.FileName), fileFromDB.FileName);
Phil Haack has a nice article where he created a Custom File Download Action Result class. You only need to specify the virtual path of the file and the name to be saved as.
I used it once and here's my code.
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Download(int fileID)
{
Data.LinqToSql.File file = _fileService.GetByID(fileID);
return new DownloadResult { VirtualPath = GetVirtualPath(file.Path),
FileDownloadName = file.Name };
}
In my example i was storing the physical path of the files so i used this helper method -that i found somewhere i can't remember- to convert it to a virtual path
private string GetVirtualPath(string physicalPath)
{
string rootpath = Server.MapPath("~/");
physicalPath = physicalPath.Replace(rootpath, "");
physicalPath = physicalPath.Replace("\\", "/");
return "~/" + physicalPath;
}
Here's the full class as taken from Phill Haack's article
public class DownloadResult : ActionResult {
public DownloadResult() {}
public DownloadResult(string virtualPath) {
this.VirtualPath = virtualPath;
}
public string VirtualPath {
get;
set;
}
public string FileDownloadName {
get;
set;
}
public override void ExecuteResult(ControllerContext context) {
if (!String.IsNullOrEmpty(FileDownloadName)) {
context.HttpContext.Response.AddHeader("content-disposition",
"attachment; filename=" + this.FileDownloadName)
}
string filePath = context.HttpContext.Server.MapPath(this.VirtualPath);
context.HttpContext.Response.TransmitFile(filePath);
}
}
Thanks to Ian Henry!
In case if you need to get file from MS SQL Server here is the solution.
public FileResult DownloadDocument(string id)
{
if (!string.IsNullOrEmpty(id))
{
try
{
var fileId = Guid.Parse(id);
var myFile = AppModel.MyFiles.SingleOrDefault(x => x.Id == fileId);
if (myFile != null)
{
byte[] fileBytes = myFile.FileData;
return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, myFile.FileName);
}
}
catch
{
}
}
return null;
}
Where AppModel is EntityFramework model and MyFiles presents table in your database.
FileData is varbinary(MAX) in MyFiles table.
its simple just give your physical path in directoryPath with file name
public FilePathResult GetFileFromDisk(string fileName)
{
return File(directoryPath, "multipart/form-data", fileName);
}
public ActionResult Download()
{
var document = //Obtain document from database context
var cd = new System.Net.Mime.ContentDisposition
{
FileName = document.FileName,
Inline = false,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
return File(document.Data, document.ContentType);
}
if (string.IsNullOrWhiteSpace(fileName))
return Content("filename not present");
var path = Path.Combine(your path, your filename);
var stream = new FileStream(path, FileMode.Open);
return File(stream, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
GetFile should be closing the file (or opening it within a using). Then you can delete the file after conversion to bytes-- the download will be done on that byte buffer.
byte[] GetFile(string s)
{
byte[] data;
using (System.IO.FileStream fs = System.IO.File.OpenRead(s))
{
data = new byte[fs.Length];
int br = fs.Read(data, 0, data.Length);
if (br != fs.Length)
throw new System.IO.IOException(s);
}
return data;
}
So in your download method...
byte[] fileBytes = GetFile(file);
// delete the file after conversion to bytes
System.IO.File.Delete(file);
// have the file download dialog only display the base name of the file return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, Path.GetFileName(file));