So this is with visual studio 2003. The code works perfect on higher frameworks however I need it in 1.1 so this is my only option. Also, the programs in german so the actual message was "Auf die methode (mymethod) wurde ohne anführungszeichen verwiesen". The code and everything is on a seperate PC so I can retrieve it if necessary but unfortunately no copy paste so for now i'm just writing as my main question how on earth is that even an error? Adding quotations doesn't work and gives the expected error complaining you can't implicitly convert method type to string. The line it failed on was FileSystemWatcher += fileSystemWatcher_Changed Theres a bunch more errors which I've managed to work around and more to fix however this is the only one thats truly stumpt me and any guidence would be useful.
I've trie using ' as quotations around it as well as * on either side. I've tried passing arguments which it uses which was of no help and honestly don't even know what else to try as I'm new to coding and it worked perfect on framework 2.0. Just not in this german 2003 1.1 framework..
Any help is kindly appreciated!
edit: Heres the related code to the error
private static void GetCurrentJob()
{
//This gets the file
string CurrentJobPath = #"C:\LuK\Master\Daten\dnocontainer.cfg";
//This makes it so it only reads the 5th line of the notepad and ignore everything else
//string line = File.ReadLines(CurrentJobPath).Skip(4).Take(1).First();
string[] lines = File.ReadAllLines(CurrentJobPath);
string line = lines[4];
//This is getting rid of all parts of the line I don't care about
line = line.Replace(" ", "").Replace("(STRING)Dno=", "").Replace("\"", "").Replace(";", "");
//This isn't necessary but I like it okay
JobName = line;
//Testing To prove its behaving
Console.WriteLine(JobName);
//This is making a path to the exact folder for the job currently running
AreaOfMonitor = #"C:\LuK\Master\Zeichnungsdaten\" + JobName;
Console.WriteLine(AreaOfMonitor);
}
private static void ProgramSwapMonitor(string ProgramChange)
{
// Create a new FileSystemWatcher and set its properties.
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = ProgramChange;
/* Watch for changes in LastAccess and LastWrite times, and
the renaming of files or directories. */
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
// Only watch this specific file
watcher.Filter = "dnocontainer.cfg";
// Add event handlers.
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.Renamed += new RenamedEventHandler(OnRenamed);
// Begin watching.
watcher.EnableRaisingEvents = true;
}
// Define the event handlers.
private static void OnChanged(object source, FileSystemEventArgs e)
{
// Specify what is done when a file is changed, created, or deleted.
Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
Console.WriteLine(Spacer);
//This disables the directory monitor, then changes the active job in its memory, then restarts the directory monitor so it can now monitor the new location, then removes the old watcherChanged instance so theres no duplicates.
fileSystemWatcher.EnableRaisingEvents = false;
GetCurrentJob();
MonitorDirectory(path);
fileSystemWatcher.Changed -= FileSystemWatcher_Changed;
public static void MonitorDirectory(string path)
{
//fileSystemWatcher.EnableRaisingEvents = false;
path = AreaOfMonitor;
//Declaring variables outside the catch for use of error handling
string ErrorHandlingPathName = path;
string ErrorPathNameMaster = "JobNameError";
string Unlikely = "";
string errorpath = #"D:\JobEditsSaved\" + ErrorPathNameMaster + ".txt";
string PathError = "This file isn't in the directory, does a new job need adding?";
string Aidpath = #"D:\JobEditsSaved\CODEISSUES.txt";
int retryName = 0;
int NewNameCount = 0;
//Trys to do the normal function of beginning monitoring of path extracted from the dnocontainer
//If the file extracted doesn't have a corrosponding folder, rather than crash the program we write an error log which
//In the backup location writes a textfile saying its had this problem and writes the name of the job it couldn't find
//If this exceptions been thrown, the name of the errorTextFile I'm creating would already exist, so I'm doing a simple
//Counter which will add a number to the end of the error file name if it exists already.
try
{
//Trys code we want to work
fileSystemWatcher.Path = path;
}
catch (IOException ex)
{
//Both these catches do the exact same thing but different exceptions. However, the exceptions are for effectively the same thing (dir not exist)
//It will try to write an error log, if an error logs been made before, it adds 1 to its name, trys again and repeats this pricess 5000 times.
//If theres serious issues leading to errors then it will make a file saying to get me to look at code cause god almighty something major must have happened.
while (retryName < 5000)
{
if (!File.Exists(errorpath))//check if error log file is existing
{
PathError = PathError + ex;
File.WriteAllText(errorpath, PathError);
Console.WriteLine(PathError);
retryName = 0;
NewNameCount = 0;
break;
}
else if (errorpath.Length <= 250)//checks that the new error log file name its giving is less than max characters for a file in wondows
{
string ErrorPathName = ErrorPathNameMaster;
NewNameCount++;
retryName++;
ErrorPathName = ErrorPathNameMaster + Convert.ToString(NewNameCount);
Console.WriteLine("ErrorFile Name exits. Attempting new file name -" + ErrorPathName);
errorpath = #"D:\JobEditsSaved\" + ErrorPathName + ".txt";
}
else if (errorpath.Length > 250)//if its more than max characters lets stop the numbers, reset them, then change part of the name and run again. Allowing double the error logs
{
NewNameCount = 0;
retryName++;
NewNameCount++;
Unlikely = "JobNameError,ClearSomeErrorsOut" + Convert.ToString(NewNameCount);
errorpath = #"D:\JobEditsSaved\" + Unlikely + ".txt";
}
else //at this point theres over 500 errors thats occured. Someone should have analyised it and seen a few and followed it up, nevermind over 500. Only scenario I see where this could happen is a glitch in code causing it to make way too many at once. Hence, call me.
{
string Jesus = "Contact me (Josh Simpson), error handling needs looking at in static void monitor directory";
File.WriteAllText(Aidpath, Jesus);
}
Console.WriteLine(Spacer);
//If everything goes wrong it will create errors then to allow it to continue running and not crash it has to monitor somewhere
//I'm making it monitor this path as its the most common one I've seen so far.
path = #"C:\LuK\Master\Zeichnungsdaten\L-01026-0G20-04";
JobName = "L-01026-0G20-04";
fileSystemWatcher.Path = path;
}
}
catch (SystemException ex)
{
while (retryName < 5000)
{
if (!File.Exists(errorpath))
{
PathError = PathError + ex;
File.WriteAllText(errorpath, PathError);
Console.WriteLine(PathError);
retryName = 0;
NewNameCount = 0;
break;
}
else if (errorpath.Length <= 250)
{
string ErrorPathName = ErrorPathNameMaster;
NewNameCount++;
retryName++;
ErrorPathName = ErrorPathNameMaster + Convert.ToString(NewNameCount);
Console.WriteLine("ErrorFile Name exits. Attempting new file name -" + ErrorPathName);
errorpath = #"D:\JobEditsSaved\" + ErrorPathName + ".txt";
}
else if (errorpath.Length > 250)
{
NewNameCount = 0;
retryName++;
NewNameCount++;
Unlikely = "JobNameError,ClearSomeErrorsOut" + Convert.ToString(NewNameCount);
errorpath = #"D:\JobEditsSaved\" + Unlikely + ".txt";
Console.WriteLine("Errors need clearing - Still making logs fine though");
}
else
{
Console.WriteLine("What manner of thing hath gone wrong, I don't actually expect any of these statements to ever be called.\r\n Is there a new job thats not been added? Or format of dnoconfig??");
string Jesus = "Contact me (Josh Simpson), error handling needs looking at in static void monitor directory";
File.WriteAllText(Aidpath, Jesus);
}
}
Console.WriteLine(Spacer);
//If everything goes wrong it will create errors then to allow it to continue running and not crash it has to monitor somewhere
//I'm making it monitor this path as its the most common one I've seen so far.
path = #"C:\LuK\Master\Zeichnungsdaten\L-01026-0G20-04";
JobName = "L-01026-0G20-04";
fileSystemWatcher.Path = path;
}
//Allows monitoring of subdirectories. - Not needed as shouldn't be any:
fileSystemWatcher.IncludeSubdirectories = true;
//Declaring the filters, I don't really know why its needed for the monitoring of changes, creation, deletion ECT but it is.
fileSystemWatcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
//Calling the SystemWatcherFunctions
fileSystemWatcher.Changed += FileSystemWatcher_Changed;
fileSystemWatcher.Error += new ErrorEventHandler(OnError);
Console.WriteLine("This is monitoring {0}{1}", path, Spacer);
//enables the monitoring
fileSystemWatcher.EnableRaisingEvents = true;
}
public static void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
//This is for the sizes and file info. We are grabbing the resutls but also creating a converted version so I can't display in MB for large file with accuracy
/*var info = new FileInfo(e.FullPath);
var size = Convert.ToInt64(0);
//declaring to be used, double allows decimals. 64bitInt does not.
double MBSIZE = 0;
//This is to avoid potential error. Ensures the info we are grabbing is in the direct directory and no sub ones.
if ((info.Attributes & FileAttributes.Directory) != FileAttributes.Directory)
{
size = info.Length;
}
//This is for making it into megabytes for unnecessary user friendliness
if (size > 2000)
{
MBSIZE = Convert.ToDouble(size);
MBSIZE = MBSIZE / 1000000;
Console.WriteLine("File Changed/Edited/saved: {0}\r\nwas modified on {1}\r\nit is {2} Megabytes in size\r\nIs was originally created on {3}", e.Name, modification, MBSIZE, creation, Spacer);
}
else
*///{
Console.WriteLine("File Changed/Edited/saved: {0}\r\nwas modified on {1}\r\nIs was originally created on {2}{3} ", e.Name, modification, creation, Spacer);
//}
//The changed Files Name, then its location, then the date it was edited, then we take that date and convert to integer string, then remove all / as not to mess with directories.
FileNameStore = e.Name;
FilesPath = e.FullPath;
DateTime FilesLastWrite = File.GetLastAccessTime(FilesPath);
string FilesLastDone = FilesLastWrite.ToString("dd/MM/yyyy-HH:mm:ss");
FilesLastDone = FilesLastDone.Replace("/", "-").Replace(":", ".");
//This will be the files name when saved, this is a combo of when It was edited and its original name
string NewFileName = FilesLastDone + "_" + JobName + "_" + FileNameStore;
string BackupLocation = #"D:\JobEditsSaved\";
PasteLocation = BackupLocation + NewFileName;
//ConsoleWrites to check everything passing what it should be
Console.WriteLine("\r\n -- NewFileName:{0}\r\n -- FilesPath:{1}\r\n -- FileNameStore:{2}\r\n -- FilesLastDone:{3}\r\n -- PasteLocation:{4}", NewFileName, FilesPath, FileNameStore, FilesLastDone, PasteLocation);
if (CanRunTime)
{
CanRunTime = false;
t.Interval = 2000;
t.Elapsed += new ElapsedEventHandler(t_Elapsed);
t.Start();
}
}```
Related
I will be amazed if I find a solution for this, since it is very specific and vague, but I figured I would try. I'll try to give as much information as humanly possible, since I've been searching for answers for some time now.
I am building a utility in C# which copies records from a file in a library on the i-series/AS400 and builds an encrypted text file with each record from the AS400 as a comma separated string. In the file, it will have values like filename, fieldvalue1, fieldvalue2, fieldvalue3. I then take that text file to another PC, and run a C# utility which copies that record into the same file name in a library over there on a different i-series machine. Unfortunately, I receive the outside bounds of the array exception in some cases, but I cannot determine why. In the record just prior to the exception, the record looks pretty much the same and it works fine. My code is below in a nutshell. I usually don't give up, but I don't expect to ever figure this out. If someone does, I'll probably sing karaoke tonight.
// Select records from AS400 file and write them to text file
Recordset rs = new Recordset();
sqlQuery = "SELECT * FROM " + dataLibrary + "." + fileName;
try
{
rs.Open(sqlQuery, con);
while (!rs.EOF)
{
int[] fieldLengths;
fieldLengths = new int[rs.Fields.Count];
String[] fieldValues;
fieldValues = new String[rs.Fields.Count];
String fullString = "";
for (i = 0; i < rs.Fields.Count; i++)
{
fieldLengths[i] += rs.Fields[i].DefinedSize;
fieldValues[i] += rs.Fields[i].Value;
}
fullString = fileName + "," + String.Join(",", fieldValues);
fullString = Functions.EncryptString(fullString);
File.AppendAllText(savefile.FileName, fullString + Environment.NewLine);
rs.MoveNext();
}
}
catch (Exception ex)
{
}
cmd.Dispose();
// This gives me a text file of filename, fieldvalue1, fieldvalue2, etc...
// Next, I take the file to another system and run this process:
while ((myString = inputFile.ReadLine()) != null)
{
int stringLength = myString.Length;
String[] valuesArray = myString.Split(',');
for (i = 0; i < valuesArray.Length; i++)
{
if (i == 0)
{
fileName = valuesArray[0];
// Create file if it doesn't exist already
createPhysicalFile(newLibrary, fileName);
SQLStatement = "INSERT INTO " + newLibrary + "." + fileName + "VALUES(";
}
else
{
if (i == valuesArray.Length - 1)
{
SQLStatement += "#VAL" + i + ")";
}
else
{
SQLStatement += "#VAL" + i + ", ";
}
}
}
try
{
using (connection)
{
try
{
connection.Open();
}
catch (Exception ex)
{
}
// Create a new SQL command
iDB2Command command = new iDB2Command(SQLStatement, connection);
for (i = 1; i < valuesArray.Length; i++)
{
try
{
command.Parameters.AddWithValue("#VAL" + i, (valuesArray[i]));
}
catch (Exception ex)
{
}
}
// Just split the array into a string to visually check
// differences in the records
String arraySplit = ConvertStringArrayToString(valuesArray);
// The query gets executed here. The command looks something
// like:
// INSERT INTO LIBNAME.FILENAME VALUES(#VAL!, #VAL2, #VAL3, #VAL4)
// There are actually 320 fields in the file I'm having a problem with,
// so it's possible I'm overlooking something. I have narrowed it down to
// field # 316 when the exception occurs, but in both cases
// field 316 is blanks (when it works and when it doesn't).
command.ExecuteNonQuery();
}
}
catch (Exception ex)
{
// Here I get the exception out of bounds error in MSCORLIB.DLL.
// Some records are added fine, while others cause this exception.
// I cannot visibly tell any major differences, nor do I see any
// errors in the AS400 job log or anything in C# that would lead me
// down a certain path.
String error = ex.Message;
}
}
For what it's worth, I found this happening one a smaller file in the system and was able to figure out what going on, after painstaking research into the code and the net. Basically, the file file has numeric fields on the i-series. Somehow, the records were written to the file on the original system with null values in the numeric fields instead of numeric values. When storing the original records, I had to do this calculation:
String fieldType = rs.Fields[i].Type.ToString();
object objValue = rs.Fields[i].Value;
if (fieldType == "adNumeric" && objValue is DBNull)
{
fieldValues[i] += "0";
}
else
{
fieldValues[i] += rs.Fields[i].Value;
}
After this, if null values were found in one of the numeric fields, it just put "0" in it's place so that when writing to the new machine, it would put a valid numeric character in there and continue on writing the rest of the values. Thanks for all the advice and moral support. :)
I have 10 txt files in Debug\Tests\Text\ (10 txt files). I need to write a program to open all 10 files and updated every single file. I'm not sure how to do it. Now, I'm actually reading the folder and getting the file name and storing the file name in an array. Below is my code:
private void getFilesName()
{
string[] fileArray = Directory.GetFiles(#"Tests\Text");
//looping through the folder and get the fileNames
for (int i = 0; i<fileArray.Length; i++)
{
MessageBox.Show(fileArray[i]); // I'm doing this is to double check i manage to get the file name.
}
}
After doing this, it do read all the text file name, but the challenge now is for me to access the filename and updating every file in it. I have also created another method just for updating the values in the txt files, below is the code:
private bool modifySQLFile()
{
string destFileName = #"Tests\Text\" // I need the fileName?
string[] fileTexts = File.ReadAllLines(destFileName);
int counter = 0;
//Processing the File
foreach(string line in fileTexts)
{
//only read those non-comments line
if(line.StartsWith("--") == false)
{
//Start to replace instances of Access ID
if(line.Contains(Variable) == true)
{
fileTexts[counter] = fileTexts[counter].Replace(Variable, textBox2.Text);
}
}
counter++;
}
//check if file exists in the backup folder
if(File.Exists("Tests\\Text\\file name "+ textBox1.Text +".sql") == true)
{
MessageBox.Show("This file already exist in the backup folder");
return false;
}
else
{
//update the file
File.WriteAllLines(destFileName, fileTexts);
File.Move(destFileName, "Tests\\Text\\file name"+ textBox1.Text +".sql");
MessageBox.Show("Completed");
return true;
}
}
Your problem seems to be passing the filename variable from the loop to the method.
In order to do what you want, add a parameter to the method:
private bool ModifySQLFile(string filename)
{
string[] fileTexts = File.ReadAllLines(filename);
// ...
}
Then call the method with this parameter:
for (int i = 0; i<fileArray.Length; i++)
{
ModifySQLFile(fileArray[i]);
}
But in general you really don't want to treat a formal language as plaintext like you do. It's very easy to break the SQL like that. What if the user wanted to replace the text "insert", or replaces something with "foo'bar"?
First, implement one (file) modification:
private bool modifySQLFile(String file) {
// given source file, let´s elaborate target file name
String targetFile = Path.Combine(
Path.GetDirectoryName(file),
String.Format("{0}{1}.sql",
Path.GetFileNameWithoutExtension(file),
textBox1.Text));
// In case you want a back up
//TODO: given source file name, elaborate back up file name
//String backUpFile = Path.Combine(...);
// Check (validate) before processing: do not override existing files
if (File.Exists(targetFile))
return false;
//TODO: what if back up file exists? Should we override it? skip?
// if line doesn't start with SQL commentary --
// and contains a variable, substitute the variable with its value
var target = File
.ReadLines(file)
.Select(line => (!line.StartsWith("--") && line.Contains(Variable))
? line.Replace(Variable, textBox2.Text)
: line);
// write modified above lines into file
File.WriteAllLines(targetFile, target);
// In case you want a back up
// Move file to backup
//File.Move(file, backUpFile);
return true;
}
Then call it in the loop:
// enumerate all the text files in the directory
var files = Directory
.EnumerateFiles("#"Tests\Text", "*.txt");
//TODO: you may want filter out some files with .Where
//.Where(file => ...);
// update all the files found above
foreach (var file in files) {
if (!modifySQLFile(file))
MessageBox.Show(String.Format("{0} already exist in the backup folder", file));
}
Please, do not do:
Use Magic values: what is #"Tests\Text\" within your modifySQLFile
Mix UI MessageBox.Show(...) and logic: modifySQLFile returns true or false and it's caller who can display message box.
Materialize when it's not required (Directory.GetFiles, File.ReadAllLines)
If you would like to edit the files in parallel. With threads you can parallelize work.
for (int i = 0; i < fileArray.Length; i++)
new Thread(UpdateFileThread).Start(fileArray[i]);
private void UpdateFileThread(object path)
{
string filePath = (string)path;
//ToDo: Edit file
}
In your case you would create 10 Threads. That solution works, but is a bad pattern if you have to deal with more than 10 files.
Below i have posted the real time code ,which i have used project
protected void btnSqlfinder_Click(object sender, EventArgs e)
{
//Defining the path of directory where all files saved
string filepath = # "D:\TPMS\App_Code\";
//get the all file names inside the directory
string[] files = Directory.GetFiles(filepath);
//loop through the files to search file one by one
for (int i = 0; i < files.Length; i++)
{
string sourcefilename = files[i];
StreamReader sr = File.OpenText(sourcefilename);
string sourceline = "";
int lineno = 0;
while ((sourceline = sr.ReadLine()) != null)
{
lineno++;
//defining the Keyword for search
if (sourceline.Contains("from"))
{
//append the result to multiline text box
TxtResult.Text += sourcefilename + lineno.ToString() + sourceline + System.Environment.NewLine;
}
if (sourceline.Contains("into"))
{
TxtResult.Text += sourcefilename + lineno.ToString() + sourceline + System.Environment.NewLine;
}
if (sourceline.Contains("set"))
{
TxtResult.Text += sourcefilename + lineno.ToString() + sourceline + System.Environment.NewLine;
}
if (sourceline.Contains("delete"))
{
TxtResult.Text += sourcefilename + lineno.ToString() + sourceline + System.Environment.NewLine;
}
}
}
}
This code will fetch the multiple files in the given directory,and show the lines as per the keyword in a separate text.
But you can easily change as per your requirement,Kindly let me know your thoughts.
Thanks
Following the code found here:
How to check if file is under source control in SharpSvn?
I'm trying to make a small utility application that will iterate over a designated folder and print out the status of all the files.
private void btnCheckSVN_Click(object sender, EventArgs e)
{
ParseSVNResults(CheckSVN());
}
private Collection<SvnStatusEventArgs> CheckSVN()
{
string path = #"C:\AMG\trunk\AMC";
if (!Directory.Exists(path))
return null;
DevExpress.Utils.WaitDialogForm wait = new DevExpress.Utils.WaitDialogForm();
wait.Caption = "Please wait, loading SVN file statuses. This may take a moment.";
wait.Caption += Environment.NewLine + path;
wait.Show();
SvnClient client = new SvnClient();
SvnStatusArgs sa = new SvnStatusArgs();
sa.Depth = SvnDepth.Infinity;
Collection<SvnStatusEventArgs> statuses;
client.GetStatus(path, sa, out statuses);
wait.Close();
return statuses;
}
private void ParseSVNResults(Collection<SvnStatusEventArgs> results)
{
if (results == null)
return;
int modified = 0;
int unversioned = 0;
foreach (SvnStatusEventArgs item in results)
{
memoEditSVNFiles.Text += item.LocalContentStatus.ToString() + " -- " + item.Path + Environment.NewLine;
if (item.LocalContentStatus.ToString() == "Modified")
modified++;
else if (item.LocalContentStatus.ToString() == "NotVersioned")
unversioned++;
}
memoEditSVNFiles.Text += Environment.NewLine + "Modified: " + modified + Environment.NewLine;
memoEditSVNFiles.Text += "Not Versioned: " + unversioned + Environment.NewLine;
memoEditSVNFiles.Text += "Total: " + results.Count;
}
When the code executes, I get a total of 147 Files & Folders. The actual folder has a few thousand files. Is it possible I'm looking at too many files and SharpSVN just quits after a while?
edit; I just tried creating about 100 text files and putting 30 into 3 folders, then 'nesting' them. So I've got;
C:\AMG\trunk\test which has ~30 files
C:\AMG\trunk\test\Folder1 which has ~30 files
C:\AMG\trunk\test\Folder1\Sub which has another 30
Without comitting this to the repository, when I run the above code on C:\AMG\trunk\test instead of the given path in my code snippet, the output says 1 total file.
So it turns out the SvnStatusArgs class has a "RetrieveAllEntries" boolean flag that defaults to false.
As the name implies, setting this true returns every file, whether it was modified / unversioned or up to date.
1 extra line in the CheckSVN() method in my original post:
SvnClient client = new SvnClient();
SvnStatusArgs sa = new SvnStatusArgs();
sa.Depth = SvnDepth.Infinity;
sa.RetrieveAllEntries = true; //the new line
Collection<SvnStatusEventArgs> statuses;
client.GetStatus(path, sa, out statuses);
My C# winforms 4.0 application has been using a thread-safe streamwriter to do internal, debug logging information. When my app opens, it deletes the file, and recreates it. When the app closes, it saves the file.
What I'd like to do is modify my application so that it does appending instead of replacing. This is a simple fix.
However, here's my question:
I'd like to keep my log file AROUND 10 megabytes maximum. My constraint would be simple. When you go to close the file, if the file is greater than 10 megabytes, trim out the first 10%.
Is there a 'better' way then doing the following:
Close the file
Check if the file is > 10 meg
If so, open the file
Parse the entire thing
Cull the first 10%
Write the file back out
Close
Edit: well, I ended up rolling my own (shown following) the suggestion to move overt to Log4Net is a good one, but the time it woudl take to learn the new library and move all my log statements (thousands) over isn't time effective for the small enhancement I was trying to make.
private static void PerformFileTrim(string filename)
{
var FileSize = Convert.ToDecimal((new System.IO.FileInfo(filename)).Length);
if (FileSize > 5000000)
{
var file = File.ReadAllLines(filename).ToList();
var AmountToCull = (int)(file.Count * 0.33);
var trimmed = file.Skip(AmountToCull).ToList();
File.WriteAllLines(filename, trimmed);
}
}
I researched this once and never came up with anything, but I can offer you plan B here:
I use the selection below to keep a maximum of 3 log files. At first, log file 1 is created and appended to. When it exceeds maxsize, log 2 and later log 3 are created. When log 3 is too large, log 1 is deleted and the remaining logs get pushed down the stack.
string[] logFileList = Directory.GetFiles(Path.GetTempPath(), "add_all_*.log", SearchOption.TopDirectoryOnly);
if (logFileList.Count() > 1)
{
Array.Sort(logFileList, 0, logFileList.Count());
}
if (logFileList.Any())
{
string currFilePath = logFileList.Last();
string[] dotSplit = currFilePath.Split('.');
string lastChars = dotSplit[0].Substring(dotSplit[0].Length - 3);
ctr = Int32.Parse(lastChars);
FileInfo f = new FileInfo(currFilePath);
if (f.Length > MaxLogSize)
{
if (logFileList.Count() > MaxLogCount)
{
File.Delete(logFileList[0]);
for (int i = 1; i < MaxLogCount + 1; i++)
{
Debug.WriteLine(string.Format("moving: {0} {1}", logFileList[i], logFileList[i - 1]));
File.Move(logFileList[i], logFileList[i - 1]); // push older log files back, in order to pop new log on top
}
}
else
{
ctr++;
}
}
}
The solutions here did not really work for me. I took user3902302's answer, which again was based on bigtech's answer and wrote a complete class. Also, I am NOT using StreamWriter, you can change the one line (AppendAllText against the StreamWrite aequivalent).
There is little error handling (e. g. re-try access when it is failing, though the lock should catch all internal concurrent access).
This might be enough for some people who had to use a big solution like log4net or nlog before. (And log4net RollingAppender is not even thread-safe, this one is. :) )
public class RollingLogger
{
readonly static string LOG_FILE = #"c:\temp\logfile.log";
readonly static int MaxRolledLogCount = 3;
readonly static int MaxLogSize = 1024; // 1 * 1024 * 1024; <- small value for testing that it works, you can try yourself, and then use a reasonable size, like 1M-10M
public static void LogMessage(string msg)
{
lock (LOG_FILE) // lock is optional, but.. should this ever be called by multiple threads, it is safer
{
RollLogFile(LOG_FILE);
File.AppendAllText(LOG_FILE, msg + Environment.NewLine, Encoding.UTF8);
}
}
private static void RollLogFile(string logFilePath)
{
try
{
var length = new FileInfo(logFilePath).Length;
if (length > MaxLogSize)
{
var path = Path.GetDirectoryName(logFilePath);
var wildLogName = Path.GetFileNameWithoutExtension(logFilePath) + "*" + Path.GetExtension(logFilePath);
var bareLogFilePath = Path.Combine(path, Path.GetFileNameWithoutExtension(logFilePath));
string[] logFileList = Directory.GetFiles(path, wildLogName, SearchOption.TopDirectoryOnly);
if (logFileList.Length > 0)
{
// only take files like logfilename.log and logfilename.0.log, so there also can be a maximum of 10 additional rolled files (0..9)
var rolledLogFileList = logFileList.Where(fileName => fileName.Length == (logFilePath.Length + 2)).ToArray();
Array.Sort(rolledLogFileList, 0, rolledLogFileList.Length);
if (rolledLogFileList.Length >= MaxRolledLogCount)
{
File.Delete(rolledLogFileList[MaxRolledLogCount - 1]);
var list = rolledLogFileList.ToList();
list.RemoveAt(MaxRolledLogCount - 1);
rolledLogFileList = list.ToArray();
}
// move remaining rolled files
for (int i = rolledLogFileList.Length; i > 0; --i)
File.Move(rolledLogFileList[i - 1], bareLogFilePath + "." + i + Path.GetExtension(logFilePath));
var targetPath = bareLogFilePath + ".0" + Path.GetExtension(logFilePath);
// move original file
File.Move(logFilePath, targetPath);
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
}
}
edit:
Since I just noticed that you asked a slightly different question: should your lines vary greatly in size, this would be a variation (, that in 90% of cases does not improve over yours, though, and might be very slightly faster, also introduced a new unhandled error (\n not being present)):
private static void PerformFileTrim(string filename)
{
var fileSize = (new System.IO.FileInfo(filename)).Length;
if (fileSize > 5000000)
{
var text = File.ReadAllText(filename);
var amountToCull = (int)(text.Length * 0.33);
amountToCull = text.IndexOf('\n', amountToCull);
var trimmedText = text.Substring(amountToCull + 1);
File.WriteAllText(filename, trimmedText);
}
}
This is derived from bigtech's answer:
private static string RollLogFile()
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string appName = Path.GetFileNameWithoutExtension(Environment.GetCommandLineArgs()[0]);
string wildLogName = string.Format("{0}*.log",appName);
int fileCounter = 0;
string[] logFileList = Directory.GetFiles(path, wildLogName, SearchOption.TopDirectoryOnly);
if (logFileList.Length > 0)
{
Array.Sort(logFileList, 0, logFileList.Length);
fileCounter = logFileList.Length - 1;
//Make sure we apply the MaxLogCount (but only once to reduce the delay)
if (logFileList.Length > MaxLogCount)
{
//Too many files - remove one and rename the others
File.Delete(logFileList[0]);
for (int i = 1; i < logFileList.Length; i++)
{
File.Move(logFileList[i], logFileList[i - 1]);
}
--fileCounter;
}
string currFilePath = logFileList[fileCounter];
FileInfo f = new FileInfo(currFilePath);
if (f.Length < MaxLogSize)
{
//still room in the current file
return currFilePath;
}
else
{
//need another filename
++fileCounter;
}
}
return string.Format("{0}{1}{2}{3:00}.log", path, Path.DirectorySeparatorChar, appName, fileCounter);
}
Usage:
string logFileName = RollLogFile();
using (StreamWriter sw = new StreamWriter(logFileName, true))
{
sw.AutoFlush = true;
sw.WriteLine(string.Format("{0:u} {1}", DateTime.Now, message));
}
This function will allow you to rotate your log based on weekdays. First time y our application will launch on Monday, will check for any existing entry for Monday Date, if not already initialized for today will discard old entries and reinitialize new file. Onwards for whole of that day, file will keep appending the text to same log file.
So, total 7 log files will be created.
debug-Mon.txt, debog-Tue.txt...
it will also add the method name which actually logged the message along with date time. very useful for general purpose use.
private void log(string text)
{
string dd = DateTime.Now.ToString("yyyy-MM-dd");
string mm = DateTime.Now.ToString("ddd");
if (File.Exists("debug-" + mm + ".txt"))
{
String contents = File.ReadAllText("debug-" + mm + ".txt");
if (!contents.Contains("Date: " + dd))
{
File.Delete("debug-" + mm + ".txt");
}
}
File.AppendAllText("debug-" + mm + ".txt", "\r\nDate: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:s") + " =>\t" + new System.Diagnostics.StackFrame(1, true).GetMethod().Name + "\t" + text);
}
I liked greggorob64's solution but also wanted to zip the old file. This has everything you need other than the part of compressing the old file to a zip, which you can find here: Create zip file in memory from bytes (text with arbitrary encoding)
static int iMaxLogLength = 2000; // Probably should be bigger, say 200,000
static int KeepLines = 5; // minimum of how much of the old log to leave
public static void ManageLogs(string strFileName)
{
try
{
FileInfo fi = new FileInfo(strFileName);
if (fi.Length > iMaxLogLength) // if the log file length is already too long
{
int TotalLines = 0;
var file = File.ReadAllLines(strFileName);
var LineArray = file.ToList();
var AmountToCull = (int)(LineArray.Count - KeepLines);
var trimmed = LineArray.Skip(AmountToCull).ToList();
File.WriteAllLines(strFileName, trimmed);
string archiveName = strFileName + "-" + DateTime.Now.ToString("MM-dd-yyyy") + ".zip";
File.WriteAllBytes(archiveName, Compression.Zip(string.Join("\n", file)));
}
}
catch (Exception ex)
{
Console.WriteLine("Failed to write to logfile : " + ex.Message);
}
}
I have this as part of the initialization / reinitialization section of my application, so it gets run a few times a day.
ErrorLogging.ManageLogs("Application.log");
I was looking through the win32 api, and I'm not even sure it's possible to do this with native win32 vfs calls, nevermind through .Net.
About the only solution I would have would be to use memory-mapped files and move the data manually, which .Net seems to support as of .Net 4.0.
Memory Mapped Files
Can someone tell me what is going to happen in this code when an error is encountered? Ideally it should continue the foreach statement until it gets to the last record, but I suspect it's stopping in the middle of the operation because when I check the number of files moved it's off by 225. If it is in fact stopping because of an error, what can I do to make it continue the loop?
I'm creating a new upload manager for our software and need to clean the old files up. There are about 715 orphaned files equaling around 750 MB after a year and a half of use because the original developers didn't write the code to correctly overwrite old files when a new one was uploaded. They also saved the files in a single directory. I can't stand that so I'm moving all of the files into a structure - Vessel Name - ServiceRequesetID - files uploaded for that service. I'm also giving the users a gridview to view and delete files they no longer need as they work the service.
protected void Button1_Click(object sender, EventArgs e)
{
GridViewRow[] rowArray = new GridViewRow[gv_Files.Rows.Count];
gv_Files.Rows.CopyTo(rowArray, 0);
int i = -1;
foreach(GridViewRow row in rowArray)
{
i++;
string _serviceRequestID = ((Label)gv_Files.Rows[row.RowIndex].FindControl("lbl_SRID")).Text;
string _vesselName = ((Label)gv_Files.Rows[row.RowIndex].FindControl("lbl_VesselID")).Text;
string _uploadDIR = Server.MapPath("uploadedFiles");
string _vesselDIR = Server.MapPath("uploadedFiles" + "\\" + _vesselName);
string _fileName = ((Label)gv_Files.Rows[row.RowIndex].FindControl("lbl_FileName")).Text;
DirectoryInfo dInfo = new DirectoryInfo(_uploadDIR);
DirectoryInfo dVessel = new DirectoryInfo(_vesselDIR);
DirectoryInfo dSRID = new DirectoryInfo(_serviceRequestID);
dInfo.CreateSubdirectory(_vesselName);
dVessel.CreateSubdirectory(_serviceRequestID);
string _originalFile = _uploadDIR + "\\" + _fileName;
string _fileFullPath = Path.Combine(Server.MapPath("uploadedFiles/" + _vesselName + "/" + _serviceRequestID + "/"), _fileName);
FileInfo NewFile = new FileInfo(_fileFullPath);
string _fileUploadPath = _vesselName + "/" + _serviceRequestID + "/" + _fileName;
string sourceFile = _originalFile;
FileInfo _source = new FileInfo(sourceFile);
string destinationFile = _fileFullPath;
try
{
{
File.Move(sourceFile, destinationFile);
movefiles.InsertNewUploadPath(Convert.ToDecimal(_serviceRequestID), 1, _fileUploadPath);
}
}
catch (Exception ex)
{
CreateLogFiles Err = new CreateLogFiles();
Err.ErrorLog(Server.MapPath("Logs/ErrorLog"), ex.Message);
}
}
_utility.MessageBox("Completed processing files.");
}
As long as the error encountered occurs within the try catch clause, the code will continue executing within the foreach loop. However, if the error occurs outside of the try catch, the function will exit and throw an error. How many files does your error log report??