I am a little stuck. I have to use the getItems method and output it to PrintItems.txt, but I am not sure how to appoach this problem.
This is my GetItems method:
public string getItems()
{
string strout = "stock items " + "\n";
foreach (Stock s in stock)
{
strout = strout + s.ToString() + "\n";
}
return strout;
}
This is my PrintItems method:
string filename = "printitems.txt";
int count = 0;
using (StreamWriter sw = new StreamWriter(filename))
{
while (count < 5 && count < stock.Count)
{
Stock t = stock[count];
sw.WriteLine(t);
count++;
}
}
It doesn't work because it doesn't write to a file at all.
You code generally should work.
But since you haven't specified full path to the text file - it will be created in the same folder where your executable file is.
If you running it from Visual Studio - it should be in your_project\bin\Debug or your_project\bin\Release folder.
You could use:
File.WriteAllText(#"C:\dummy.txt", strout);
(As long as you don't expect the string to be massive - i.e. 10MB)
'File' uses System.IO
If you made no copy & paste error then there are 4 possibilities for your pheonomenon:
string filename = "printitems.txt";
int count = 0;
using (StreamWriter sw = new StreamWriter(filename))
{
while (count < 5 && count < stock.Count)
{
Stock t = stock[count];
sw.WriteLine(t.ToString());
count++;
}
}
You had no { after the streamwriter using line was something I saw first. The second thing is that Stock t normally can't be written directly but instead you need to do the same thing as when printing it out to the console.
Third: your code does not say anything about if stock is filled or not.
Fourth: The file: You should specify a directory (not only the filename) as else it can be that it is tried to create the file in a location where you have no permissions to create a file in (normally if you put no additional path info in the same path as where the application runs in is used [if you start from the visual studio itself then the appropraite bin path] as location where the file would be created).
Additionally: You should put a try catch block around the whole thing as there can be unexpected phenomenons which result in an exception.
Related
I need to create a file, write one line of text in the file and then delete the file and estimate how long it will take to do it.
Unfortunately, I am running in couple of problems, first I cannot write in the file, it succesfully creates it but nothing is written to it.
Secondly, I cannot delete the file because it has been used by another process.
Please help.
I have been trying to delete it for quite some time.
I have also tried wrapping it in usings, to no avail.
Writing to the file is the same situation. I even changed it so the file ends in .txt but that does not make any difference.
public static void ProcessFile(string path)
{
string fullpath = path;
int lastBracket = path.LastIndexOf("\\");
// the filename does not contain .html so it can be named to .txt
string newFileName = path.Substring(lastBracket + 1, path.Length - lastBracket - 6) + " hrefcount.txt";
string newPath = Path.Combine(fullpath.Substring(0, lastBracket), newFileName);
Console.WriteLine(newPath);
int counter = 0;
foreach (var line in File.ReadAllLines(path))
{
if (line.Contains("href="))
{
counter++;
}
}
var fileCreated = File.CreateText(newPath);
fileCreated.WriteLine("The number of times href appears is " + counter);
Console.WriteLine();
File.Delete(newPath);
}
File created, nothing written to it, unable to delete due to has been used by another process.
Instead of File.CreateText() use File.WriteAllText(path, content). It writes the text and then closes the file allowing you to delete it if necessary
Instead of the following
var fileCreated = File.CreateText(newPath);
fileCreated.WriteLine("The number of times href appears is " + counter);
You may write
File.WriteAllText(newPath, $"The number of times href appears is {counter}");
Refer documentation here
The issue with your approach is that CreateText() is used to write to a stream. But in your case, it is not necessary since you're writing all the text at once to the file and that text is small in size.
The cause of your error is the fact that you don't close and dispose the variable fileCreated. This, is a FileStream and until you close and dispose this variable the file is not available to anyone, even your own code that has opened the file.
So the first thing to do is
using (var fileCreated = File.CreateText(newPath))
{
fileCreated.WriteLine("The number of times href appears is " + counter);
}
The using block ensure the proper disposal of the variable.
However there are other parts of your code that you can simplify
public static void ProcessFile(string path)
{
string folder = Path.GetDirectoryName(path);
string file = Path.GetFileName(path);
// Keep the first 6 characters from the source file?
string newFile = file.Substring(0, 6) + " hrefcount.txt";
string newPath = Path.Combine(folder, newFile);
// A single line to retrieve your counter thanks to IEnumerables and Linq
int counter = File.ReadLines(path).Count(x => x.Contains("href="));
// Create, but dispose also the file
using (var fileCreated = File.CreateText(newPath))
{
fileCreated.WriteLine("The number of times href appears is " + counter);
}
// Now you should be free to delete the file
File.Delete(newPath);
}
I cannot delete the file because it has been used by another process.
Probably you're not disposed your files after creating. To do that, you should additionally use FileStream.Dispose method:
File.Create(path).Dispose();
estimate how long it will take to do it
You can use System.Diagnostics.Stopwatch class to do that:
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
/*
do the magic
*/
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
You can use File.WriteAllText method instead of File.CreateText to write your text to file:
File.WriteAllText(path, myText);
Remember that since the .NET 4 you can use this method with array or List<T> too instead of string.
File.Create() supports Dispose method which help you to release that file resource to perform further operations
To perform operations on file follow below steps:
Create file and free up the resource using Dispose().
File.Create(newPath).Dispose();
or Use StreamWriter to create file and write text to it.
using( StreamWriter sw = new StreamWriter(newPath, true)
{
sw.Write($"The number of times href appears is {counter}"); //Used string interpolation
}
StreamWriter calls Dispose() function to release file resource.
When Writer release control over file, then you will not face issue related to I cannot delete the file because it has been used by another process.
Now you can delete file using,
File.Delete(newPath);
MSDN : IDisposable.Dispose Method
Performs application-defined tasks associated with freeing, releasing,
or resetting unmanaged resources.
Within outlook I have various DocumentItems in folders such as the inbox and I am trying to save these to the file system within a drag/drop event.
Here is the code:
for (var i = 1; i <= _application.ActiveExplorer().Selection.Count; i++)
{
var temp = _application.ActiveExplorer().Selection[i];
var documentItem = (temp as DocumentItem);
if (documentItem == null)
continue;
var tempFileName = Path.GetTempPath() + documentItem.Subject;
documentItem.SaveAs(tempFileName);
}
They seem to save successfully and have file sizes:
But when I try to open any of them they all say they cannot be opened so they are corrupted somehow, does anyone have any ideas?
You are calling SaveAs without specifying the format, and Outlook Object Model defaults it to olMsg. You end up with an MSG file with a JPG extension.
What you need to do is loop though all attachments in the DocumentItem.Attachments collection and call Attachment.SaveAsFile. You might also want to use the Attachmeent.FileName property.
Just a general comment - multiple dot notation is evil, especially in a loo:
Selection selection = _application.ActiveExplorer().Selection;
for (var i = 1; i <= selection.Count; i++)
{
var temp = selection[i];
var documentItem = (temp as DocumentItem);
...
I have thousands of .log files and I need to find some string in all of the files.
I will explain with example: on all of .log files I have string calles "AAA" and after that string I have anumber that can be diffrenet from one log file to other log file. I know how to search the AAA string. what I dont knew is how to crop only the string number that is after the AAA string.
update:
the .log file containes a lot of lines.
on the .log file I have only 1 line that contains the string "A12A".
after that line I have anumber (for examle: 5465).
what I need is to extract the number after the A12A.
note: there is a spacing between the A12A to the 5465 string number.
example:
.log file : "assddsf dfdfsd dfd A12A 5465 dffdsfsdf dfdf dfdf "
what I need to extract: 5465.
what I have so far is:
// Modify this path as necessary.
string startFolder = #"c:\program files\Microsoft Visual Studio 9.0\";
// Take a snapshot of the file system.
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(startFolder);
// This method assumes that the application has discovery permissions
// for all folders under the specified path.
IEnumerable<System.IO.FileInfo> fileList = dir.GetFiles("*.*", System.IO.SearchOption.AllDirectories);
string searchTerm = #"Visual Studio";
// Search the contents of each file.
// A regular expression created with the RegEx class
// could be used instead of the Contains method.
// queryMatchingFiles is an IEnumerable<string>.
var queryMatchingFiles =
from file in fileList
where file.Extension == ".htm"
let fileText = GetFileText(file.FullName)
where fileText.Contains(searchTerm)
select file.FullName;
// Execute the query.
Console.WriteLine("The term \"{0}\" was found in:", searchTerm);
foreach (string filename in queryMatchingFiles)
{
Console.WriteLine(filename);
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
// Read the contents of the file.
static string GetFileText(string name)
{
string fileContents = String.Empty;
// If the file has been deleted since we took
// the snapshot, ignore it and return the empty string.
if (System.IO.File.Exists(name))
{
fileContents = System.IO.File.ReadAllText(name);
}
return fileContents;
}
I would recommend the following code for doing the search itself:
private static readonly string _SearchPattern = "A12A";
private static readonly Regex _NumberExtractor = new Regex(#"\d+");
private static IEnumerable<Tuple<String, int>> FindMatches()
{
var startFolder = #"D:\";
var filePattern = #"*.htm";
var matchingFiles = Directory.EnumerateFiles(startFolder, filePattern, SearchOption.AllDirectories);
foreach (var file in matchingFiles)
{
// What encoding do your files use?
var lines = File.ReadLines(file, Encoding.UTF8);
foreach (var line in lines)
{
int number;
if (TryGetNumber(line, out number))
{
yield return Tuple.Create(file, number);
// Stop searching that file and continue with the next one.
break;
}
}
}
}
private static bool TryGetNumber(string line, out int number)
{
number = 0;
// Should casing be ignored??
var index = line.IndexOf(_SearchPattern, StringComparison.InvariantCultureIgnoreCase);
if (index >= 0)
{
var numberRaw = line.Substring(index + _SearchPattern.Length);
var match = _NumberExtractor.Match(numberRaw);
return Int32.TryParse(match.Value, out number);
}
return false;
}
The reasons are that when doing I/O operations, the drive itself is normally the bottleneck. So it doesn't make sense to do anything in parallel or to read a lot of data from the file into memory without using it.
By using the Directory.EnumerateFiles method the drive will be searched lazily and you can start examining the first file, right after it was found. The same holds true for the File.ReadLines method. It lazily iterates through the file while you are searching for your pattern.
Through this approach you should get a maximum speed (depending on your hard-drive performance) cause it makes the minimum needed I/O calls needed to get the files and content to your code.
I have this method below, which when the user clicks the button, the program gets a list of files from a path, and zips them to a location (as long as the paths exist)
I have tested it, and it works well for small folders. When I get over 1gb, the gui was freezing. As a result, I started a new thread to stop that from happening. I tried various ways of getting the progress to display, but I get nothing.
If I manually close the program several minutes in, I get a various size temp file depending on how long I wait, so I know that it is writing the file, I just cant figure out how to tell the progress to show the user.
Any ideas?
Here is my method:
private void btnSyncJobs_Click(object sender, EventArgs e)
{
string startPath = #"J:\TV\Game Of Thrones";
string zipPath = #"j:\result.zip";
string sendPath = #"j:\";
if (Directory.Exists(startPath) && Directory.Exists(sendPath))
{
//MessageBox.Show("Correct","These 2 paths exist.");
if (File.Exists(zipPath))
{
File.Delete(zipPath); //delete existing file in order to save the new one
}
String[] allfiles = System.IO.Directory.GetFiles(startPath, "*.*", System.IO.SearchOption.AllDirectories);
int fileCount = allfiles.Length;
int filesAdded = 0;
double percentComplete = 0.00;
string fileCountString = Convert.ToString(fileCount);
MessageBox.Show("There are " + fileCountString + " files.","Count Notice.");
//create the new zip file
//ZipFile.CreateFromDirectory(startPath, zipPath, CompressionLevel.Fastest, true);
Task.Factory.StartNew(() =>
{
using (ZipFile zip = new ZipFile())
{
if (chkPassword.Checked)
{
zip.Password = txtPassword.Text;
}
foreach (string s in allfiles)
{
zip.AddItem(s);
//filesAdded++;//increment the count of files added
//percentComplete = filesAdded / fileCount;
//string percentLabel = filesAdded + " of "+ fileCount + " completed.";
//lblSyncJobsStatus.Text = percentLabel;
}
zip.Save(zipPath);
}
});
lblSyncJobsStatus.Text = "Completed successfully.";
}
else
{
MessageBox.Show("Error: One or more network drives are not attached.","Error");
lblSyncJobsStatus.Text = "Did not complete successfully.\n Please contact tech support.";
}
}
Just a note- I was testing in my tv folder to test on larger file sizes.
The line '//lblSyncJobsStatus.Text = percentLabel;' had to be commented out, because it can't update a value started in another thread. Even before that, I noticed that it was at 100% before the file was being written.
The ZipFile class does not appear to offer any events or callback opportunities to report progress.
If you're open to using the open source 7-Zip library instead (and the SevenZipSharp .NET wrapper), it looks like it provides a callback for reporting progress.
https://sevenzipsharp.codeplex.com/SourceControl/latest#SevenZip/ArchiveUpdateCallback.cs
This question already has an answer here:
Modify the content of specific line in text file
(1 answer)
Closed 8 years ago.
I'm having a textfile say something like this:
#TITLE:What's Up
#ARTIST:4 Non Blondes - Whats Up
#MP3:Four Non Blondes - Whats Up.mp3
#COVER:4 Non Blondes - Whats Up [CO].jpg
#BACKGROUND:4 Non Blondes - Whats Up [CO].jpg
#BPM:135
#GAP:32100
it's saved as 4 Non Blondes - Whats Up.txt
In the same folder there's a MP3 file which is in this example: 4 Non Blondes - Whats Up.mp3
What i want is to replace the line:
#MP3:Four Non Blondes - Whats Up.mp3
into this line:
#MP3:4 Non Blondes - Whats Up.mp3
Every MP3 line has infront of the line this:
#MP3:[Songname].mp3
I know i can do this manually but i have like 2k files like this, and they all need to link to the correct mp3 file. I'm trying this in C#, but without luck.
This is what i've tried so far:
private static void testMethod(string path)
{
var x = System.IO.Directory.GetDirectories(path);
foreach (var directory in x)
{
string[] mp3Files = System.IO.Directory.GetFiles(directory, "*.mp3");
string[] txtFiles = System.IO.Directory.GetFiles(directory, "*.txt");
string MP3FileNameWithExtensions = System.IO.Path.GetFileName(mp3Files[0]);
Console.WriteLine(txtFiles[0]);
var lines = System.IO.File.ReadAllLines(txtFiles[0]);
for (int i = 0; i < lines.Length; i++)
{
if(lines[i].Contains("#MP3")){
Console.WriteLine("Jeeeej working");
lines[i] = "#MP3:"+MP3FileNameWithExtensions;
System.IO.File.WriteAllLines(txtFiles[0], lines);
}
}
}
}
As the filename of the .txt file is [Songname].txt, you can use Path.GetFilenameWithoutExtension(files[i]) to get [Songname]. Then replace the #MP3 line with the filename + ".mp3". Now write out the file.
N.B. You will probably want to make a copy of the directory you are working on just in case something goes wrong.
I know I am late to the party but here is an example.
public void FixTheFiles(String startFolderPath)
{
foreach (String dirName in Directory.GetDirectories(startFolderPath))
{
FixTheFiles(dirName);
}
foreach (String fileName in Directory.GetFiles(startFolderPath))
{
FileInfo fi = new FileInfo(fileName);
if (fi.Extension.Equals("MP3"))
{
String fileContents = "";
using (StreamReader sr = new StreamReader(File.Open(fileName.Replace(".mp3",".txt"),FileMode.Open)))
{
String currentLine = sr.ReadLine();
if (currentLine.StartsWith("#MP3:"))
{
currentLine = "#MP3:" + fileName.Substring(fileName.LastIndexOf('\\')+1);
}
fileContents += currentLine;
}
using (StreamWriter sw = new StreamWriter(File.Open(fileName.Replace(".mp3",".txt"),FileMode.Open)))
{
sw.Write(fileContents);
}
}
}
}
I would simutaneously open a stream reader and a stream writer (with a different file name) and go through each file one line at a time searching for whatever changes you need to make. You can select your file names with an openfiledialog with Multiselect = true or run this command in a command prompt window to generate a textfile to paste in your code with quotation marks around them as initial values for a string array instantiation.
dir *.mp3 /b > filenames.txt
string[] array = new string[] {"file0.mp3",
"file1.mp3",
"file2.mp3",
"file3.mp3",
"file4.mp3",
"file5.mp3"};