blah blah blah is here! blah blah » Close

up1down
link

I want to do something like this:

(1) Check for existence of file with certain extension ".txt" in a directory D:\test
(2) If a file does not exist, create a initial one, write something to it, and name it test_1.txt
(2) If a file exists, write and append something to it, and renamed it to the next incremental number.
For example, if test_1.txt exists, renamed it to test_2.txt, after write and append.
if test_21.txt exists, renamed it to test_22.txt, after write and append.
(3) The maximum it can go is 65535.
(4) If test_65535.txt exists, create another new file and named it test_65535_1.txt, and write something to it.
If test_65535_20.txt exists, renamed it to test_65535_21.txt, after write and append.
(4) If test_65535_65535.txt exists, create another new file and named it test_65535_65535_1.txt, and write something to it.
If test_65535_65535_38.txt exists, renamed it to test_65535_65535_39.txt, after write and append.
And the loops goes on and on...

I would appreciate if some test codes are given.
thanks.

last answered one year ago

8 answers

up1down
link

Provided that there will never be more than one file in the directory whose name satisfies the pattern, this code should work:

using System;
using System.IO;

class Program
{
static void Main()
{
string dirName = @"D:\test";
string filter = "test_*.txt";
string[] fileNames = Directory.GetFiles(dirName, filter);
StreamWriter sw = null;
if (fileNames.Length == 0)
{
sw = new StreamWriter(dirName + @"\test_1.txt");
sw.WriteLine("Something"); // or whatever
sw.Close();
}
else
{
string currentName = fileNames[0];
sw = new StreamWriter(currentName, true); // append mode
sw.WriteLine("Something else"); // or whatever
sw.Close();

int first = currentName.LastIndexOf("_") + 1;
int last = currentName.Length - 4;
int number = int.Parse(currentName.Substring(first, last - first));
string newName;
if (number < 65535)
{
++number;
newName = currentName.Substring(0, first) + number.ToString() + ".txt";
}
else
{
newName = currentName.Substring(0, first + 5) + "_1.txt";
}
File.Move(currentName, newName); // rename
}
}
}

hi Vulpes, thank very much for your code. Could you explain those numbers 4 and 5: int last = currentName.Length - 4; is the number 4 due to the text 'test'? how about first+5 ? Could we code the number 4 and 5 to be more generic? as I would need to replace "test_123.txt" with other like "payload_123.setl"

up0down
link

also, when I tested with a file with payload_65535.setl existing in the directory, when the above code is executed, that existing file is appended and renamed to payload_65535_1.setl. That is not what I want.

I want to keep the existing payload_65535.setl file as it is, and create a brand new file with filename payload_65535_1.setl

thanks in advance, vulpes

up2down
link

Sorry, I didn't read the instructions properly :(

I'll try again and also make it more generic:

using System;
using System.IO;

class Program
{
static void Main()
{
// set these variables first
string dirName = @"D:\test";
string firstName = "payload_1.setl";
string filter = "payload_*.setl";
string extension = ".setl"; // including the dot

string[] fileNames = Directory.GetFiles(dirName, filter);
StreamWriter sw = null;
if (fileNames.Length == 0)
{
sw = new StreamWriter(dirName + "\\" + firstName);
sw.WriteLine("Something"); // or whatever
sw.Close();
}
else
{
string currentName = null;
if (fileNames.Length == 1)
{
currentName = fileNames[0];
}
else
{
// get longest file name which will be current one
int maxLen = fileNames[0].Length;
int maxIndex = 0;
for(int i = 1; i < fileNames.Length; i++)
{
if (maxLen < fileNames[i].Length)
{
maxLen = fileNames[i].Length;
maxIndex = i;
}
}
currentName = fileNames[maxIndex];
}

int first = currentName.LastIndexOf("_") + 1;
int last = currentName.Length - extension.Length;
int number = int.Parse(currentName.Substring(first, last - first));
string newName;
if (number < 65535)
{
++number;
newName = currentName.Substring(0, first) + number.ToString() + extension;
sw = new StreamWriter(currentName, true); // append mode
sw.WriteLine("Something else"); // or whatever
sw.Close();
File.Move(currentName, newName); // rename
}
else
{
newName = currentName.Substring(0, first + 5) + "_1" + extension;
// create new file
sw = new StreamWriter(newName);
sw.WriteLine("Something new"); // or whatever
sw.Close();
}
}
}
}

thank you very much Vulpes for your wonderful and neat codes... could I confirm with you that first + 5 is due to the length of the extension ".setl" ?

vulpes
17279

That's strange - I thought I'd commented on that point but the comment seems to have disappeared! Anyway, when first + 5 is used, we know that the number preceding the extension is 65535 and 'first' corresponds to the index of its first digit. As we're now going to add '_1' to that we need to jump over the 65535 and so we add 5 to 'first'.

I understood now. thanks once again.

up0down
link

hi Vulpes, for your existing code, it works well. Now, I want to save the same set of data in both the local drive, as well as the network drive in the server. How do I do it? I could not get it saved to my server drive directory created. thanks.

DateTime dt = DateTime.Now;
string yyyyMMdd = String.Format("{0:yyyyMMdd}", dt);

// to save the same set of data on the server
DirectoryInfo dir = new DirectoryInfo(@"\\192.168.1.101\\D$\\SharedFolder");
try
{
dir.CreateSubdirectory("test");
dir.CreateSubdirectory(@String.Concat(@"test\payload_", yyyyMMdd));
}
catch (IOException e)
{
Console.WriteLine(e.Message);
}

up1down
link

I think the problem lies with this line:

DirectoryInfo dir = new DirectoryInfo(@"\\192.168.1.101\\D$\\SharedFolder");

When you use a backslash in a C# string, you either need to double it or precede the string with an @ sign but not both. Now, you're doing both, so if you make all backslashes after the first (as it's followed by an IP address) single backslashes then it should work:
DirectoryInfo dir = new DirectoryInfo(@"\\192.168.1.101\D$\SharedFolder");

up0down
link

hi Vulpes,
The below code is able to write to both local drive, as well as the remote drive. I want to include the yyyyMMdd string to the directory for the remote drive, but it does not seem to work. Why?

// string dirName_Server = @String.Concat("\\192.168.1.101\\D$\\SharedFolder\\test\\payload_", yyyyMMdd); // not ok


using System;
using System.IO;

class Program
{
static void Main()
{
// set these variables first
DateTime dt = DateTime.Now;
string yyyyMMdd = String.Format("{0:yyyyMMdd}", dt);
string dirName = @String.Concat("D:\\test\\payload_", yyyyMMdd);

string dirName_Server = @"\\192.168.1.101\D$\SharedFolder\test\payload"; // ok
// string dirName_Server = @String.Concat("\\192.168.1.101\\D$\\SharedFolder\\test\\payload_", yyyyMMdd); // not ok

string firstName = "payload_1.setl";
string filter = "payload_*.setl";
string extension = ".setl"; // including the dot

DirectoryInfo di = Directory.CreateDirectory(dirName); // create the directory.
DirectoryInfo di_Server = Directory.CreateDirectory(dirName_Server); // create the directory.

string[] fileNames = Directory.GetFiles(dirName, filter);
string[] fileNames_Server = Directory.GetFiles(dirName_Server, filter);

StreamWriter sw = null;
StreamWriter sw1 = null;
if (fileNames.Length == 0 | fileNames_Server.Length==0)
{
sw = new StreamWriter(dirName + "\\" + firstName);
sw.WriteLine("Something"); // or whatever
sw.Close();

sw1 = new StreamWriter(dirName_Server + "\\" + firstName);
sw1.WriteLine("Something"); // or whatever
sw1.Close();
}
else
{
string currentName = null;
string currentName_Server = null;
if (fileNames.Length == 1 | fileNames_Server.Length==1)
{
currentName = fileNames[0];
currentName_Server = fileNames_Server[0];
}
else
{
// get longest file name which will be current one
int maxLen = fileNames[0].Length;
int maxLen_Server = fileNames_Server[0].Length;
int maxIndex = 0;
int maxIndex_Server = 0;
for (int i = 1; i < fileNames.Length; i++)
{
if (maxLen < fileNames[i].Length)
{
maxLen = fileNames[i].Length;
maxIndex = i;
}
}
for (int i = 1; i < fileNames_Server.Length; i++)
{
if (maxLen_Server < fileNames_Server[i].Length)
{
maxLen_Server = fileNames_Server[i].Length;
maxIndex_Server = i;
}
}
currentName = fileNames[maxIndex];
currentName_Server = fileNames_Server[maxIndex_Server];
}

int first = currentName.LastIndexOf("_") + 1;
int last = currentName.Length - extension.Length;
int number = int.Parse(currentName.Substring(first, last - first));
string newName;

int first_Server = currentName_Server.LastIndexOf("_") + 1;
int last_Server = currentName_Server.Length - extension.Length;
int number_Server = int.Parse(currentName_Server.Substring(first_Server, last_Server - first_Server));
string newName_Server;

if (number < 65535 | number_Server < 65535)
{
++number; ++number_Server;
newName = currentName.Substring(0, first) + number.ToString() + extension;
newName_Server = currentName_Server.Substring(0, first_Server) + number_Server.ToString() + extension;

sw = new StreamWriter(currentName, true); // append mode
sw.WriteLine("Something else"); // or whatever
sw.Close();

sw1 = new StreamWriter(currentName_Server, true); // append mode
sw1.WriteLine("Something else"); // or whatever
sw1.Close();

File.Move(currentName, newName); // rename
File.Move(currentName_Server, newName_Server); // rename
}
else
{
newName = currentName.Substring(0, first + 5) + "_1" + extension;
// create new file
sw = new StreamWriter(newName);
sw.WriteLine("Something new"); // or whatever
sw.Close();

newName_Server = currentName_Server.Substring(0, first_Server + 5) + "_1" + extension;
sw1 = new StreamWriter(newName_Server);
sw1.WriteLine("Something new"); // or whatever
sw1.Close();
}
}
}
}

up0down
link

The first few lines of code should be:

// set these variables first
DateTime dt = DateTime.Now;
string yyyyMMdd = String.Format("{0:yyyyMMdd}", dt);
string dirName = String.Concat("D:\\test\\payload_", yyyyMMdd);

string dirName_Server = String.Concat(@"\\192.168.1.101\D$\SharedFolder\test\payload_", yyyyMMdd);

A couple of further points:

1. There's no need to precede String.Concat with an @ sign, even if it's concatenating verbatim strings. The compiler just ignores it and it looks strange to anyone reading the code.

2. Unless you're doing bit arithmetic, you should normally use the conditional operators (&&, ||) rather than their logical equivalents (&, |). This is because the former don't bother evaluating the second operand unless it might make a difference to the value of the whole expression, which saves clock cycles.

The only case where you wouldn't do this is if the evaluation of the second operand has side effects (say, it's the result of a method call) which you're relying on though, IMO, this is seldom good practice.

up0down
link

thank you Vulpes for your help and comments, it is useful. :)

Feedback