StreamWriter to project directory and sub directory? - c#

I'm currently having an issue with my application and I'm starting to think it's just my logic. I can't figure it out even after browsing these forms and MSDN.
I'm trying to use StreamWriter to create a text document in my app directory and create sub folder containing that document. Currently it just keeps dumping the file in my apps exe directory.
string runTimeDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string recipeDirectory = Path.Combine(runTimeDirectory, "Recipes");
if (!Directory.Exists(recipeDirectory))
{
//Recipes directory doesnt exist so create it
Directory.CreateDirectory(recipeDirectory);
}
// Write text to file
using (StreamWriter OutputFile = new StreamWriter(recipeDirectory + RecipeName + #".txt"))
{

Try this:
using (StreamWriter OutputFile = new StreamWriter(
Path.Combine(recipeDirectory, RecipeName + #".txt")))
The reason I think is that your recipeDirectory and RecipeName + #".txt" aren't separated by the backslash, so the file is written to the parent directory instead and named recipeDirectory + RecipeName + #".txt".
As an aside, I would also recommend you pass your RecipeName through a sanitizer function like this in case any name contains characters that can't be used in a file name:
internal static string GetSafeFileName(string fromString)
{
var invalidChars = Path.GetInvalidFileNameChars();
const char ReplacementChar = '_';
return new string(fromString.Select((inputChar) =>
invalidChars.Any((invalidChar) =>
(inputChar == invalidChar)) ? ReplacementChar : inputChar).ToArray());
}

Related

How do I specify a specific file in my Xamarin/VisualStudio Project using Environment.SpecialFolder?

I am trying to append text to a text file, but I can't find anywhere how to actually locate an existing file.
partial void MainBtn_TouchUpInside(UIButton sender)
{
var Pp = ("Selected Form Of Exchange: Paypal");
string mydocpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments(WHAT DO I WRITE IN THIS SPACE??);
using (StreamWriter outputFile = new **StreamWriter(Path.Combine(mydocpath, "SelectPayment.txt")))
//I know that the file already exists, I just am trying different things.
{
outputFile.WriteLine(Pp);
}
So what do I do? Thanks
Josh
you specify a file by combining a folder path and a file name to create a file path
// this returns the path to a folder
string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
// combine that with a file name to create a file path
string file = Path.Combine(path, "myFile.text");
// append text to file
File.AppendAllText(file, "this is the text I want to append);

i have to Create Folder in bin-debug and then create and write in text file in it

i wrote this code , it ctreates folder named "Fitness50" each time but the text file is not created.i want to create textfile within this folder and then save values of an arraylist.
so for i have tried this
DirectoryInfo myDir = new DirectoryInfo(#"E:");
ParentFolderName1 = "Fittness50";
myDir.CreateSubdirectory(ParentFolderName1);
myDir = new DirectoryInfo(ParentFolderName1);
ParentFolderName1 = "Fittness50";
myDir.CreateSubdirectory(ParentFolderName1);
FileName1 = "./" + "" + ParentFolderName1 + "" + "/" + "Fittness10" + "" + "" + PopulationID + "" + ".txt";
FileStream fs2 = new FileStream(FileName1, FileMode.Create, FileAccess.Write);
StreamWriter SW2 = new StreamWriter(fs2);
for (i = 0; i < AlTargetData.Count; i++)
{
SW2.WriteLine(AlTargetData[i]);
}
AlTargetData.Clear();
SW2.Close();
fs2.Close();
Well, first of all, / is not the preferred directory separator on Windows, but \ is. Just because / happens to work, there's no reason to use it. Secondly, you're not creating the Fittness10 folder at all, but you're creating Fittness50 twice. And third, you're not writing the file to the folders you create, but to the current working directory ..
Your code (or at least what I understand you want to achieve) can be shortened significantly to this:
string path = #"E:\Fittness50\Fittness10";
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
string fileName = Path.Combine(path, String.Format("{0}.txt", PopulationID));
File.WriteAllText(fileName, String.Join(Environment.NewLine, AlTargetData));
Please note that you should not consider writing to bin\debug. There will be no bin\debug on the end-user's machine. If the user installs your application, it will be most probably be installed in the Program Files folder, which your application won't be allowed to write to. Instead, consider writing to a common location, like the ones you can chose from in Environment.GetFolderPath.

IO Exception - File being used by another process (Can't open file following directory creation)

I have got a project on the go that monitors patients for a vet while they are being operated on and writes the result to a text file. While I was experimenting with the outputting I just let the files save in the Debug folder, which worked fine. However, I've now created a full directory that creates or opens a main folder, and then a sub folder (based on input text from the program), to save the text file into.
private void createDirectory()
{ //create output file in this folder using owner name and current date
//main folder path (contains all files output from system)
string rootDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\Horse Monitoring Records";
//sub folder path (each patient has individual subfolder)
string subDirectory = rootDirectory + "\\" + txtPatName.Text + "-" + txtOwnerName.Text;
//file name (patient has file created for each operation)
fileName = subDirectory + "\\" + txtOwnerName.Text + "-" + DateTime.Now.Date.ToString("ddMMyyyy") + ".txt";
if (!Directory.Exists(rootDirectory)) //if main folder does not exist...
{
Directory.CreateDirectory(rootDirectory); //create it in My Documents
}
if (!Directory.Exists(subDirectory)) //if patient sub folder does not exist...
{
Directory.CreateDirectory(subDirectory); //create it in Patient-Owner format
}
if (!File.Exists(fileName)) //if monitoring file does not exist...
{
File.Create(fileName); //create it in Owner-Date format
}
}
This stage works fine, but as soon as you try to save some data to the text file, it throws to a run time error stating that
The file cannot be accessed because it is being used by another process.
The exception is brought up here:
private void saveFileDetails()
{
//Once case details have been entered, create new file using these details and add data input structure
StreamWriter consoleFile = new StreamWriter(fileName);
...
}
When I went and checked out the folder, the relevant sub-folder and file had been created but the text file was blank.
I'm guessing it's something to do with closing the text file after creating the directory, which means it's already open when the system tries to open it. I can't figure out how to sort this issue out though!
The two functions shown above are called like this:
private void btnStart_Click(object sender, EventArgs e)
{
...
//file details entered upon load written to new file - according to PatID
createDirectory();
saveFileDetails();
}
Any suggestions on where to go from here would be very much appreciated!
Thanks,
Mark
The issue here is that you do
if (!File.Exists(fileName)) //if monitoring file does not exist...
{
File.Create(fileName); //create it in Owner-Date format
}
Right before you try to write to the file. Because you've just created it (if it didn't exist), chances are that the operating system hasn't released the file yet.
Like #Jauch mentioned in the comments, you could skip this check completely and use the StreamWriter overload which will create file if it doesn't exist, or append to it if it does.
private void saveFileDetails()
{
//Once case details have been entered, create new file using these details and add data input structure
using (StreamWriter consoleFile = new StreamWriter(fileName, true))
{
// ...
}
}
Alternatively you can use the following to write all of your text at once:
File.AppendAllText(textToWrite, fileName);
File.Create(fileName) returns an open stream to the file which is never closed.
To create an empty file use File.WriteAllBytes(fileName, new byte[0]);
Otherwise the 2 methods can be shortend
private void SaveFileDetails()
{
string subDirectory = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"Horse Monitoring Records");
// create the folder hierarchy if not exists. does nothing if already there
Directory.CreateDirectory(subDirectory);
// each patient has individual file
var filepath = Path.Combine(subDirectory,
txtPatName.Text + "-" + txtOwnerName.Text + "-" + DateTime.Now.Date.ToString("yyyyMMdd") + ".txt");
// creates the file if not exists
using (var writer = new StreamWriter(filepath, append: true, encoding: Encoding.UTF8))
{
// write details
}
}
Note:
merged 2 methods
.NET naming conventions applied
changed dateformat to better sort by name in explorer
StreamWriter implements IDisposable, so wrapping it in a using block can manage closing and disposing the writer and ensuring it is available the next time you want to touch that file. It can also manage creating the text file if it doesn't exist, removing the need to explicitly call File.Create.
StreamWriter consoleFile = new StreamWriter(fileName);
becomes
using (StreamWriter writer = File.AppendText("log.txt"))
{
// writing, etc.
}
or
using (StreamWriter writer = new StreamWriter(fileName, true))
{ // true says "append to file if it exists, create if it doesn't"
// writing, etc.
}
Whatever seems more readable to you will work fine.

Edit an argument with a loop

I am attempting to alter a series of 4 .bat files. When I run the program, it prompts me for an input and then writes it to the .bat file.
I took the code below from the microsoft documentation on File.Openwrite, then added some variables to point to the files.
As opposed to copy/pasting the code that actually writes the text, I put a for loop around it with the intent of altering the argument so that the File.OpenWrite piece will look to a different variable (and so a different path/directory) during each iteration. I confirmed that the loop works (if I enter one of the path# variables it will iterate through and write to that file 4 times) and that File.OpenWrite is seeing the correct text each iteration. My only guess is that it is looking at the 'path#' argument literally and not seeing it as a variable. Can someone help me understand how I can alter this argument through iteration?
using System;
using System.IO;
using System.Text;
class Test
{
public static void Main()
{
string path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
string path0 = path + #"\down_fa.bat";
string path1 = path + #"\down_ng.bat";
string path2 = path + #"\down_os.bat";
string path3 = path + #"\down_sp.bat";
string portinput = Console.ReadLine();
string dotbatinput = "DDL -p" + portinput;
// Open the stream and write to it.
for (int i = 0; i < 4; i++)
{
using (FileStream fs = File.OpenWrite("path" + i))
{
Byte[] info =
new UTF8Encoding(true).GetBytes(dotbatinput);
// Add some information to the file.
fs.Write(info, 0, info.Length);
}
}
}
}
You cannot refer to a variable declared in your code using a string and concatenating a number. In this way you pass a literal string to the OpenWrite method not the content of the variable with the name equals to your string.
A simpler approach is to add every batch file to a list of strings and then loop over that list writing the content required
string path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
List<string> batFiles = new List<string>();
batFiles.Add(System.IO.Path.Combine(path, "down_fa.bat"));
batFiles.Add(System.IO.Path.Combine(path, "down_ng.bat"));
batFiles.Add(System.IO.Path.Combine(path, "down_os.bat"));
batFiles.Add(System.IO.Path.Combine(path, "down_sp.bat"));
string portinput = Console.ReadLine();
string dotbatinput = "DDL -p" + portinput;
foreach(string batFile in batFiles)
{
using (FileStream fs = File.OpenWrite(batFile))
{
-----
}
}
File.OpenWrite("path" + 0) != File.OpenWrite(path0)
The left side opens a stream to a file called "path0" which you will find in the bin\Debug directory of your project and the right example writes a file at the location specified in the string path0. The same of course applies to the other numbers. A possible solution would be to use an array or a list:
string[] paths = new string[4].Select(x => System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)).ToArray();
string[0] += ...;
string[1] += ...;
string[2] += ...;
string[3] += ...;
foreach (string path in paths)
{
using (FileStream fs = File.OpenWrite(path))
{
// do stuff
}
}

How to write at the next line in the next opening of the csv file?

At first run, my program, writes to a csv file in the first line,
But, when I'm running my program at the second.. third.. time, it runs over the first line..
how can i correct it?
I would like to have a CSV file input of all the entering to my program.
The code is as follows:
private void WriteToCsvFile()
{
var us = users.ElementAt(0);
string names = "Number',";
string userAnswer = (us.userName + ",");
foreach (string ss in user)
{
string str = Path.GetFileName(ss);
names = names + str + ",";
}
foreach (string ans in us.answer)
{
userAnswer = userAnswer + ans + ",";
}
using (StreamWriter sw = new StreamWriter("EntranceLog.csv"))
{
sw.WriteLine(names);
sw.WriteLine(userAnswer);
}
this.Close();
}
Add true parameter in the constructor:
using (StreamWriter sw = new StreamWriter("EntranceLog.csv", true))
The second parameter named append controls whether an existing file shall be overwritten or appended. MSDN states:
true to append data to the file; false to overwrite the file. If the specified file does not exist, this parameter has no effect, and the constructor creates a new file.
Each time it is run, you are creating a new file with the same name is overwriting the older file. That is the default behavior of the specific constructor you are using.
You want to use this constructor instead and specify the append parameters as true:
using (StreamWriter sw = new StreamWriter("EntranceLog.csv", true))
{
// write your file as normal
}

Categories