StreamWriter and FileStream errors on file create - c#

I have a Save ActionResult in my Controller that is set up to use StreamWriter. The code works perfectly, for saving to a file that exists.
Save Action
[HttpPost]
[ValidateInput(false)]
public ActionResult Save(string fileName, string startTemplateUrl, string html)
{
string directoryname = Path.GetDirectoryName(fileName);
string filename = Path.GetFileName(fileName);
var lines = html;
var helper = (Server.MapPath(directoryname));
using (StreamWriter outputFile = new StreamWriter(Path.Combine(helper, filename)))
{
outputFile.WriteLine(lines);
return View();
}
}
I am now working on a file creation and from what i have read you can do this with StreamWriter although when I try to implement it, it says it cannot be found. Which tells me it is looking for a file instead of creating it.
So I tried to implement this using FileInfo. It appears that it has everything it needs but just doesn't save it. Below is my latest code. It does not like the
fs.Write(lines);
I had a try catch block. on this and it had the same results. That it cannot find it.
[HttpPost]
[ValidateInput(false)]
public ActionResult Create (string fileName, string startTemplateUrl, string html)
{
string directoryname = Path.GetDirectoryName(fileName);
string filename = Path.GetFileName(fileName);
var lines = html;
var helper = (Server.MapPath(directoryname));
var file = "Test\\" + filename;
var pathString = System.IO.Path.Combine(helper, "Test\\", filename);
FileInfo fi = new FileInfo(pathString);
if (fi.Exists)
{
fi.Delete();
}
using (FileStream fs = fi.Create())
{
fs.Write(lines);
return View();
}
}
Thanks for your help!
Update:
This is the message I get. Below the message I have the actual string to the directory copied from folder explorer..
Exception thrown: 'System.IO.DirectoryNotFoundException' in mscorlib.dll
An exception of type 'System.IO.DirectoryNotFoundException' occurred in mscorlib.dll but was not handled in user code
Could not find a part of the path 'C:\Users\Scott\source\repos\HMIBuilder\HMIBuilder\Files\HMIBuider\Test\Test2.html'.
C:\Users\Scott\source\repos\HMIBuilder\HMIBuilder\Files\HMIBuilder\Test
Update:
I need to look at my code better! This is fixed.. The code at the very top works perfectly for both save and create. The problem was in the javascript code variables that i was feeding it. A Typo... If you look at the above comparison, which I did not catch myself, too many long nights I suppose, HMIBuilder is spelled HMIBuider... in the error.

using (StreamWriter outputFile = new StreamWriter(Path.Combine(path, "filename.txt")))
would create a new file, if needed.
Your problem may be the Test directory and CreateDirectory is here to help.
DirectoryInfo di = Directory.CreateDirectory(path);
If we put the writing to the file and creating directories together it could look like the following snippet.
var path = "./MyFiles/SpecialFiles";
var filename = "thisIsAVerySpecialFile.txt";
Directory.CreateDirectory(path);
//Create a new file or overwrite existing (i.e. *not* append)
using (var f = new StreamWriter(Path.Combine(path, filename)))
{
f.WriteLine("Hello world!");
}
Without Directory.CreateDirectory the code results in System.IO.DirectoryNotFoundException with 'Could not find a part of the path '(...)'.

Related

ASP .NET Core Web API - Getting and extracting a .zip file from upload controller, using IFormFile

I have an API Upload Controller, which has a parameter IFormFile. From Swagger, I am passing a .zip file which has a few .json files inside. I want to get these .json files from that .zip that I receive from Swagger and pass them to a service that will process them.
So I managed to create a logic like this. I save the .zip file in (~Temp>settings) directory, the next thing I want to do is unzip that file and send the .json files into a different directory named "temp-json-imports". So then I can get the .json files and work with them.
Here is the code that I have written so far, this doesn't work, it fails on the last line - (ZipFile.ExtractToDirectory(filePath, tmpJsonImports);), with an exception of type System.IO.IOException (like shown in the picture below).
Any ideas on how can I solve this problem would be very much welcome. :)
[HttpPost("import/{applicationId}")]
public async Task<IActionResult> ImportSettings([FromRoute] Guid applicationId, IFormFile file)
{
string tempPath = Path.Combine(_hostingEnvironment.ContentRootPath, Path.GetTempPath());
string tmpSettingsPath = Path.Combine(tempPath, "settings");
string tmpImportSettings = Path.Combine(tmpSettingsPath, "import");
string tmpJsonImports = Path.Combine(tmpImportSettings, "temp-json-imports");
Directory.CreateDirectory(tmpSettingsPath);
Directory.CreateDirectory(tmpImportSettings);
Directory.CreateDirectory(tmpJsonImports);
long size = file.Length;
if (size > 0)
{
var filePath = tmpImportSettings + "\\" + file.FileName;
using var stream = new FileStream(filePath, FileMode.Create);
await file.CopyToAsync(stream);
string zipPath = Path.GetFileName(filePath);
ZipFile.ExtractToDirectory(filePath, tmpJsonImports);
}
return Ok();
}
Try to use your code on my application, it will show this exception:
This exception relates the following code, you didn't close the file handle after copy the file to the path.
var filePath = tmpImportSettings + "\\" + file.FileName;
using var stream = new FileStream(filePath, FileMode.Create);
await file.CopyToAsync(stream);
To solve this exception, try to modify your code as below:
if (size > 0)
{
var filePath = tmpImportSettings + "\\" + fileviewmodel.File.FileName;
using (var stream = new FileStream(filePath, FileMode.Create))
{
await fileviewmodel.File.CopyToAsync(stream);
};
string zipPath = Path.GetFileName(filePath);
ZipFile.ExtractToDirectory(filePath, tmpJsonImports);
}

Write lines in file when the file exists c#

i try to write line in file when this exists:
My code is next:
string strRuta = "C:\File.txt"
if (!Directory.Exists(strRuta))
Directory.CreateDirectory(strRuta);
string psContenido = "Hola";
if (!(File.Exists(strRuta + strNombreArchivo)))
{
swArchivo = File.CreateText(strRuta + strNombreArchivo);
}
if (!psContenido.ToLower().Contains("error"))
{
swArchivo.WriteLine(psContenido);
swArchivo.Flush();
swArchivo.Close();
swArchivo.Dispose();
File.SetCreationTime(strRuta + strNombreArchivo, DateTime.Now);
}
but when run this program i have a error in WriteLine, i donĀ“t undertand which is the reason, could you help me?
I would like to know how to write in the file(in the next line the word)
There are a couple of problems, I think. First, you're specifying what looks like a file name and creating a directory with that name (not sure if this is intentional or not). Second, you can use the static helper method AppendAllText of the File class to both create the file if it doesn't exist, and to write the contents to the end of the file. It handles all the streamwriter stuff for you, so you don't have to worry about calling close and dispose.
private static void Main(string[] args)
{
string directory = #"C:\private\temp";
string fileName = "MyFile.txt";
string filePath = Path.Combine(directory, fileName);
string fileContents = "This will be written to the end of the file\r\n";
// This will create the directory if it doesn't exist
Directory.CreateDirectory(directory);
// This will create the file if it doesn't exist, and then write the text at the end.
File.AppendAllText(filePath, fileContents);
File.SetCreationTime(filePath, DateTime.Now);
}

Storing and getting back files from MongoDB

I am working on c# .Net 4.5
I have to upload some files on MongoDB and in other module, I have to get them back based on metadata.
for that I am doing like below,
static void uploadFileToMongoDB(GridFSBucket gridFsBucket)
{
if (Directory.Exists(_sourceFilePath))
{
if (!Directory.Exists(_uploadedFilePath))
Directory.CreateDirectory(_uploadedFilePath);
FileInfo[] sourceFileInfo = new DirectoryInfo(_sourceFilePath).GetFiles();
foreach (FileInfo fileInfo in sourceFileInfo)
{
string filePath = fileInfo.FullName;
string remoteFileName = fileInfo.Name;
string extension = Path.GetExtension(filePath);
double fileCreationDate = fileInfo.CreationTime.ToOADate();
GridFSUploadOptions gridUploadOption = new GridFSUploadOptions
{
Metadata = new BsonDocument
{{ "creationDate", fileCreationDate },
{ "extension", extension }}
};
using (Stream fileStream = File.OpenRead(filePath))
gridFsBucket.UploadFromStream(remoteFileName, fileStream, gridUploadOption);
}
}
}
and downloading,
static void getFileInfoFromMongoDB(GridFSBucket bucket, DateTime startDate, DateTime endDate)
{
double startDateDoube = startDate.ToOADate();
double endDateDouble = endDate.ToOADate();
var filter = Builders<GridFSFileInfo>.Filter.And(
Builders<GridFSFileInfo>.Filter.Gt(x => x.Metadata["creationDate"], startDateDoube),
Builders<GridFSFileInfo>.Filter.Lt(x => x.Metadata["creationDate"], endDateDouble));
IAsyncCursor<GridFSFileInfo> fileInfoList = bucket.Find(filter); //****
if (!Directory.Exists(_destFilePath))
Directory.CreateDirectory(_destFilePath);
foreach (GridFSFileInfo fileInfo in fileInfoList.ToList())
{
string destFile = _destFilePath + "\\" + fileInfo.Filename;
var fileContent = bucket.DownloadAsBytes(fileInfo.Id); //****
File.WriteAllBytes(destFile, fileContent);
}
}
in this code (working but) I have two problems which I am not sure how to fix.
If i have uploaded a file and I upload it again, it actually gets
uploaded. How to prevent it?
Ofcourse both uploaded files have different ObjectId but while uploading a file I will not be knowing that which files are already uploaded. So I want a mechanism which throws an exception if i upload already uploaded file. Is it possible? (I can use combination of filename, created date, etc)
If you have noticed in code, actually i am requesting to database server twice to get one file written on disk, How to do it in one shot?
Note lines of code which I have marked with "//****" comment. First I am querying into database to get fileInfo (GridFSFileInfo). I was expecting that I could get actual content of file from this objects only. But I didnot find any related property or method in that object. so I had to do var fileContent = bucket.DownloadAsBytes(fileInfo.Id); to get content. M I missing something basic here ?

C# streamwriter denies access to save xml file into MyDocuments

I created a little game with the option to save the character into an XML File, now I wanted the Savegame-Folder location to be at MyDocuments, but every time I try to save the XML I just get an access denied from my streamwriter. Does someone know how to fix that?
Here's my code:
// Create the folder into MyDocuments (works perfectly!)
Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), #"Arena\Savegames\"));
// This one should the save the file into the directory, but it doesn't work :/
path = Path.GetDirectoryName(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + #"\Arena\Savegames\" + hero.created + ".xml"));
The Streamwriter:
public class SaveLoadGame
{
public void SaveGameData(object IClass, string filename)
{
StreamWriter saveGameWriter = null;
try
{
XmlSerializer saveGameSerializer = new XmlSerializer((IClass.GetType()));
saveGameWriter = new StreamWriter(filename);
saveGameSerializer.Serialize(saveGameWriter, IClass);
}
finally
{
if (saveGameWriter != null)
saveGameWriter.Close();
saveGameWriter = null;
}
}
}
public class LoadGameData<T>
{
public static Type type;
public LoadGameData()
{
type = typeof(T);
}
public T LoadData(string filename)
{
T result;
XmlSerializer loadGameSerializer = new XmlSerializer(type);
FileStream dataFilestream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
try
{
result = (T)loadGameSerializer.Deserialize(dataFilestream);
dataFilestream.Close();
return result;
}
catch
{
dataFilestream.Close();
return default(T);
}
}
}
I tried some of the solutions I found here on stackoverflow like this and this. But didn't work for me, maybe someone else has an idea how I can get access to that folder? Or maybe just save it somewhere I actually have access, because ApplicationData and CommonApplicationData didn't work for me either.
Btw I'm using Virtual Box with Win10_Preview, I hope it's not because of this.
Edit: Before trying to save the files to MyDirectory I managed to save the files into my Debug folder of the project like this:
path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + #"\Savegames\" + hero.created + ".xml";
gameSaver.SaveGameData(myCharacterObject, path);
Thanks to Jon Skeet I figured out that I was just using the directory name, instead of the full path to save my file. So I just fixed the code to this:
// Creating the folder in MyDocuments
Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), #"Arena\Savegames\"));
// Setting the full path for my streamwriter
path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + #"\Arena\Savegames\" + hero.created + ".xml";

C#: Creating a new FileInfo in a directory that you have the DirectoryInfo of

I was just wondering when you have for example:
var dir = new DirectoryInfo(#"C:\Temp");
Is there an easier/clearer way to add a new file to that directory than this?
var file = new FileInfo(Path.Combine(dir.FullName, "file.ext"));
I'm thinking I can probably just make an extension method or something, but curious if something already exists that can't see here... I mean the DirectoryInfo does have GetFiles() method for example.
What is it that you want to do? The title says "Creating a new file". A FileInfo object is not a file; it's an object holding information about a file (that may or may not exist). If you actually want to create the file, there are a number of ways of doing so. One of the simplest ways would be this:
File.WriteAllText(Path.Combine(dir.FullName, "file.ext"), "some text");
If you want to create the file based on the FileInfo object instead, you can use the following approach:
var dir = new DirectoryInfo(#"C:\Temp");
var file = new FileInfo(Path.Combine(dir.FullName, "file.ext"));
if (!file.Exists) // you may not want to overwrite existing files
{
using (Stream stream = file.OpenWrite())
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write("some text");
}
}
As a side note: it is dir.FullName, not dir.FullPath.
Why don't you use:
File.Create(#"C:\Temp\file.ext");
or
var dir = new DirectoryInfo(#"C:\Temp");
File.Create(dir.FullName + "\\file.ext");
While there does exist Directorynfo.GetFiles() methods, they only return files that actually exist on disk. Path.Combine is about hypothetical paths.
Try these extension methods:
public static FileInfo CombineWithFileName(this DirectoryInfo directoryInfo, string fileName)
{
return new FileInfo(Path.Combine(directoryInfo.Name, fileName));
}
public static DirectoryInfo CombineWithDirectoryName(this DirectoryInfo directoryInfo, string directoryName)
{
return new DirectoryInfo(Path.Combine(directoryInfo.Name, directoryName));
}

Categories