C# Sequential file output - c#

I have a C# winform application that is outputting to excel files.
Let's say the name format of the file name is: Output1.xlsl
I would like to have the output saved to another sequential file on each button click/execution.
So next it would be Output2.xlsl, Output3.xlsl... etc.
How to check that, I know of checking if the file exists, but how to check for the numbering?
FileInfo newExcelFile = new FileInfo(#"Output1.xlsx");
if (newExcelFile.Exists)
{
...
}

You could use this loop and File.Exists with Path.Combine:
string directory = #"C:\SomeDirectory";
string fileName = #"Output{0}.xlsx";
int num = 1;
while (File.Exists(Path.Combine(directory, string.Format(fileName, num))))
num++;
var newExcelFile = new FileInfo(Path.Combine(directory, string.Format(fileName, num)));
In general the static File methods are more efficient than always creating a FileInfo instance.

We use a method similar to this to achieve this:
/// <param name="strNewPath">ex: c:\</param>
/// <param name="strFileName">ex: Output.xlsx</param>
/// <returns>Next available filename, ex: Output3.xlsx</returns>
public static string GetValidFileName(string strNewPath, string strFileName)
{
var strFileNameNoExt = Path.GetFileNameWithoutExtension(strFileName);
var strExtension = Path.GetExtension(strFileName);
var intCount = 1;
while (File.Exists(Path.Combine(strNewPath, strFileNameNoExt + intCount + strExtension)))
intCount++;
return Path.Combine(strNewPath, strFileNameNoExt + intCount + strExtension);
}

Just wrap it in a while loop
int num = 1;
FileInfo newExcelFile = new FileInfo("Output1.xlsx");
while(newExcelFile.Exists)
{
newExcelFile = new FileInfo("Output" + num + ".xlsx");
num++;
}

I would find the newest file in the folder and use its number as a basis to start from. If there are no other programs to write there, this should be sufficient.
DirectoryInfo di = new DirectoryInfo("Some folder");
FileInfo fi = di.GetFiles().OrderByDescending(s => s.CreationTime).First();
string fileName = fi.Name;
//....

You can do a simple loop:
FileInfo newExcelFile = null;
for (int i = 0; i < int.MaxValue; i++)
{
newExcelFile = new FileInfo(string.Format(#"Output{0}.xlsx", i));
if (!newExcelFile.Exists)
{
break;
}
newExcelFile = null;
}
if (newExcelFile == null)
{
// do you want to try 2147483647
// or show an error message
// or throw an exception?
}
else
{
// save your file
}

It may not be most efficient one but I can suggest following solution
split the file name with "."
Remove substring "Output" from it
Now sort to get the maximum number.

It depends on the logic. What should happen if you had Output1.xlsx Output2.xlsx Output3.xlsx and removed Output2.xlsx, should the new file be Output2.xlsx or Output4.xlsx?
If you want to have always the highest number for the new files, you can use similar code
int lastNum = 0;
string[] files = Directory.GetFiles("c:\\myDir", "Output*.xlsx");
if (files.Length > 0)
{
Array.Sort(files);
lastNum = Convert.ToInt32(Regex.Match(files[files.Length - 1], "Output[\\d](*).xlsx").Result("$1"));
lastNum++;
}
FileInfo newExcelFile = new FileInfo("Output" + lastNum + ".xlsx");
Of course you can loop, but it's not a good idea if you have thousands of files. For small amount of files it could be fine
int i = 0;
for (; i < Int32.MaxValue; i++)
{
if (File.Exists("Output" + i + ".xlsx"))
break;
}

Related

C# Extract json object from mixed data text/js file

I need to parse reactjs file in main.451e57c9.js to retrieve version number with C#.
This file contains mixed data, here is little part of it:
.....inally{if(s)throw i}}return a}}(e,t)||xe(e,t)||we()}var Se=
JSON.parse('{"shortVersion":"v3.1.56"}')
,Ne="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgA
AASAAAAAqCAYAAAATb4ZSAAAACXBIWXMAAAsTAAALEw.....
I need to extract json data of {"shortVersion":"v3.1.56"}
The last time I tried to simply find the string shortVersion and return a certain number of characters after, but it seems like I'm trying to create the bicycle from scratch. Is there proper way to identify and extract json from the mixed text?
public static void findVersion()
{
var partialName = "main.*.js";
string[] filesInDir = Directory.GetFiles(#pathToFile, partialName);
var lines = File.ReadLines(filesInDir[0]);
foreach (var line in File.ReadLines(filesInDir[0]))
{
string keyword = "shortVersion";
int indx = line.IndexOf(keyword);
if (indx != -1)
{
string code = line.Substring(indx + keyword.Length);
Console.WriteLine(code);
}
}
}
RESULT
":"v3.1.56"}'),Ne="data:image/png;base64,iVBORw0KGgoAA.....
string findJson(string input, string keyword) {
int startIndex = input.IndexOf(keyword) - 2; //Find the starting point of shortversion then subtract 2 to start at the { bracket
input = input.Substring(startIndex); //Grab everything after the start index
int endIndex = 0;
for (int i = 0; i < input.Length; i++) {
char letter = input[i];
if (letter == '}') {
endIndex = i; //Capture the first instance of the closing bracket in the new trimmed input string.
break;
}
}
return input.Remove(endIndex+1);
}
Console.WriteLine(findJson("fwekjfwkejwe{'shortVersion':'v3.1.56'}wekjrlklkj23klj23jkl234kjlk", "shortVersion"));
You will recieve {'shortVersion':'v3.1.56'} as output
Note you may have to use line.Replace('"', "'");
Try below method -
public static object ExtractJsonFromText(string mixedStrng)
{
for (var i = mixedStrng.IndexOf('{'); i > -1; i = mixedStrng.IndexOf('{', i + 1))
{
for (var j = mixedStrng.LastIndexOf('}'); j > -1; j = mixedStrng.LastIndexOf("}", j -1))
{
var jsonProbe = mixedStrng.Substring(i, j - i + 1);
try
{
return JsonConvert.DeserializeObject(jsonProbe);
}
catch
{
}
}
}
return null;
}
Fiddle
https://dotnetfiddle.net/N1jiWH
You should not use GetFiles() since you only need one and that returns all before you can do anything. This should give your something you can work with here and it should be as fast as it likely can be with big files and/or lots of files in a folder (to be fair I have not tested this on such a large file system or file)
using System;
using System.IO;
using System.Linq;
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
var path = $#"c:\SomePath";
var jsonString = GetFileVersion(path);
if (!string.IsNullOrWhiteSpace(jsonString))
{
// do something with string; deserialize or whatever.
var result=JsonConvert.DeserializeObject<List<Version>>(jsonString);
var vers = result.shortVersion;
}
}
private static string GetFileVersion(string path)
{
var partialName = "main.*.js";
// JSON string fragment to find: doubled up braces and quotes for the $# string
string matchString = $#"{{""shortVersion"":";
string matchEndString = $#" ""}}'";
// we can later stop on the first match
DirectoryInfo dir = new DirectoryInfo(path);
if (!dir.Exists)
{
throw new DirectoryNotFoundException("The directory does not exist.");
}
// Call the GetFileSystemInfos method and grab the first one
FileSystemInfo info = dir.GetFileSystemInfos(partialName).FirstOrDefault();
if (info.Exists)
{
// walk the file contents looking for a match (assumptions made here there IS a match and it has that string noted)
var line = File.ReadLines(info.FullName).SkipWhile(line => !line.Contains(matchString)).Take(1).First();
var indexStart = line.IndexOf(matchString);
var indexEnd = line.IndexOf(matchEndString, indexStart);
var jsonString = line.Substring(indexStart, indexEnd + matchEndString.Length);
return jsonString;
}
return string.Empty;
}
public class Version
{
public string shortVersion { get; set; }
}
}
Use this this should be faster - https://dotnetfiddle.net/sYFvYj
public static object ExtractJsonFromText(string mixedStrng)
{
string pattern = #"\(\'\{.*}\'\)";
string str = null;
foreach (Match match in Regex.Matches(mixedStrng, pattern, RegexOptions.Multiline))
{
if (match.Success)
{
str = str + Environment.NewLine + match;
}
}
return str;
}

iTextSharp .NET PDF - unable to change PDF Producer

I am using iTextSharp product to change the PDF properties as follows.
I am unable to change the "PDF Producer" property at all. Please suggest, where am i getting wrong.
The code line
info["Producer"] = "My producer";
is not working as it should be.
string sourcePath = tbPath.Text;
IList<string> dirs = null;
string pdfName = string.Empty;
string OutputPath = string.Empty;
DirectoryInfo di = new DirectoryInfo(sourcePath);
DirectoryInfo dInfo = Directory.CreateDirectory(sourcePath + "\\" + "TempDir");
OutputPath = Path.Combine(sourcePath,"TempDir");
dirs = Directory.GetFiles(di.FullName, "*.pdf").ToList();
for (int i = 0; i <= dirs.Count - 1; i++)
{
try
{
PdfReader pdfReader = new PdfReader(dirs[i]);
using (FileStream fileStream = new FileStream(Path.Combine(OutputPath, Path.GetFileName(dirs[i])),
FileMode.Create,
FileAccess.Write))
{
PdfStamper pdfStamper = new PdfStamper(pdfReader, fileStream);
Dictionary<string, string> info = pdfReader.Info;
info["Title"] = "";
info["Author"] = "";
info["Producer"] = "My producer"; ////THIS IS NOT WORKING..
pdfStamper.MoreInfo = info;
pdfStamper.Close();
pdfReader.Close();
}
You can only change the producer line if you have a license key. A license key needs to be purchased from iText Software. Instructions on how to apply the license key are sent along with that key.
If you want to use iText for free, you can't change the producer line. See the license header of every file in the open source version of iText:
* In accordance with Section 7(b) of the GNU Affero General Public License,
* a covered work must retain the producer line in every PDF that is created
* or manipulated using iText.
For your info: iText Group has successfully sued a German company that changed the producer line without purchasing a license. You can find some documents related to this case here: IANAL: What developers should know about IP and Legal (slide 57-62)
By the way, I won a JavaOne Rockstar award with this talk: https://twitter.com/itext/status/704278659012681728
Summarized: if you don't have a commercial license for iText, you can not legally change the producer line in iText. If you have a commercial license, you need to apply the license key.
If you are using known producer, you can replace bytes in PDF file.
You need producer to be at least length of your Company (or producer replacement text) name.
In this example I'm assuming that producer has at least 20 chars. You have to determine that by editing PDF file with text editor.
Before using this check licence for the program used to create PDF
Here is an example in C#.
// find producer bytes: "producer... " in array and replace
// them with "COMPANY", and after fitth with enough spaces (code: 32)
var textForReplacement = "producer";
var bytesForReplacement = System.Text.Encoding.UTF8.GetBytes(textForReplacement);
var newText = "COMPANY";
var newBytes = System.Text.Encoding.UTF8.GetBytes(newText);
var result = this.Search(pdf, bytesForReplacement);
if (result > -1)
{
var j = 0;
for (var i = result; i < result + 20; i++)
{
// if we have new bytes, then replace them
if (i < result + newBytes.Length)
{
pdf[i] = newBytes[j];
j++;
}
// if not, fill spaces (32)
else
{
pdf[i] = 32;
}
}
}
return pdf;
}
int Search(byte[] src, byte[] pattern)
{
int c = src.Length - pattern.Length + 1;
int j;
for (int i = 0; i < c; i++)
{
if (src[i] != pattern[0]) continue;
for (j = pattern.Length - 1; j >= 1 && src[i + j] == pattern[j]; j--) ;
if (j == 0) return i;
}
return -1;
}

Auto Incrementing file names?

I have a list of files like so
abc.txt
pas.txt
tempr.txt
What I would like to do is to append english alphabets to theese file names ..
the result should look like this
abc_a.txt
pas_b.txt
tempr_c.txt
This process should continue till the last character (i.e 'z'). if there are more files then the file names would become
abc_a.txt
pas_b.txt
tempr_c.txt
.................
filename_z.txt
anotherfilename_a001.txt
Notice that the counter was again reset to the first character except an integer was attached to it.
This is the code that i have right now. Please note that it is NOT working ..
string alphabets= "abcdefghijklmnopqrstuvwxyz";
List<string> filenames = new List<string>();
filenames.Add("test1.txt");
filenames.Add("newfile.cs");
filenames.Add("test2.txt");
filenames.Add("newfile2.cs");
string currentFileNmae = string.Empty;
foreach(string s in filenames) {
char usedAlphabet = new char();
for(int i = 0;i<=alphabets.Length-1;i+=11) {
usedAlphabet.Dump();
alphabets[i].Dump();
if(usedAlphabet != alphabets[i] )
{
if(currentFileNmae!= s)
{
string.Format("{0}--{1}",s,alphabets[i]).Dump();
usedAlphabet = alphabets[i];
currentFileNmae = s;
}
}
break;
}
}
I am part of a team that's building a file renamer tool for our internal purposes and hence i need this code. This is part of the our enumertation functionality that we have planned.
Please suggest.
thanks
Try starting here:
using System.Diagnostics;
using System.IO;
string filename = #"C:\Foo\Bar.txt";
for (int count = 0; count < 100; count++)
{
char letter = (char)((int)'a' + count % 26);
string numeric = (count / 26) == 0 ? "" : (count / 26).ToString("000");
Debug.Print(Path.GetFileNameWithoutExtension(filename) + "_" + letter + numeric + Path.GetExtension(filename));
}
Substitute your own loop to go through the filenames and use Path to manipulate the pieces/parts of the names.
The renaming, IIRC, can be handled by File.Move. Surround it with a try/catch to implement the name collision logic.
Had no coffee yet, but this should do.
List<string> files = new List<string>();
int charIndex = 0;
int numericIndex = -1;
foreach (var file in files.Select(path => new FileInfo(path)))
{
// Create new Filename - This may needs some tuning
// to really remove only the extension ad the end
// It doesnt take care of things like
// file.bmp.bmp.bmp ...
string newFileName = String.Format("{0}_{1}{2}.{3}",
file.FullName.Replace(file.Extension,String.Empty),
(char)(charIndex++ + 97),
(numericIndex > -1 ? String.Format("{0:D4}", numericIndex) : String.Empty),
file.Extension);
// Rename the File
file.MoveTo(newFileName);
// Increment Counters.
if (charIndex > 25)
{
charIndex = 0;
numericIndex++;
}
}
You can try something like this
const string directory = #"C:\\wherever";
string[] fiNames = new string[]{ "abc", "pas", "etc",};
char[] alphabet = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
int x = 0;
string ending = "";
for(int i = fiNames.Count()-1; i>=0; i--)
{
if(x%26==0)
{
x=0
if( ending=="")
ending="1";
else
ending=(System.Convert.ToInt32(ending)+1).ToString();
}
System.IO.File.Move(directory+fiNames[i], fiNames[i]+alphabet[x].ToString()+ending);
x++;
}

copy half the files to one place and other half to other c#

if i have 4 files. and i want to move half of them to disc 1 and half of them to disc 2.
if im using the:
Directory.Move(source, destination)
im guessing i can change to source by doing a foreach loop + an array or list,
but how could i change the destination after half the source files are transfered and then transfer the other half to the new destination?
string[] files = ... // create a list of files to be moved
for (int i = 0; i < files.Length; i++)
{
var sourceFile = files[i];
var destFile = string.Empty;
if (i < files.Length / 2)
{
destFile = Path.Combine(#"c:\path1", Path.GetFileName(sourceFile));
}
else
{
destFile = Path.Combine(#"d:\path2", Path.GetFileName(sourceFile));
}
File.Move(sourceFile, destFile);
}
UPDATE:
Here's a lazy approach which doesn't require you to load all the file names in memory at once which could be used for example in conjunction with the Directory.EnumerateFiles method:
IEnumerable<string> files = Directory.EnumerateFiles(#"x:\sourcefilespath");
int i = 0;
foreach (var file in files)
{
var destFile = Path.Combine(#"c:\path1", Path.GetFileName(file));
if ((i++) % 2 != 0)
{
// alternate the destination
destFile = Path.Combine(#"d:\path2", Path.GetFileName(file));
}
File.Move(sourceFile, destFile);
}
The simple answer is that you would move the individual files instead.
Use a Directory.GetFiles(source) to get a list of files in the folder, get a .Count() of that and then loop through each file and move it.
public void MoveFilesToSplitDestination(string source, string destination1, string destination2)
{
var fileList = Directory.GetFiles(source);
int fileCount = fileList.Count();
for(int i = 0; i < fileCount; i++)
{
string moveToDestinationPath = (i < fileCount/2) ? destination1 : destination2;
fileList[i].MoveTo(moveToDestination);
}
}
int rubikon= files.Count() / 2;
foreach (var file in files.Take(rubikon))
file.Move(/* first destination */));
foreach (var file in files.Skip(rubikon))
file.Move(/* second destination */));

Getting path relative to the current working directory? [duplicate]

This question already has answers here:
How to get relative path from absolute path
(24 answers)
Closed 7 years ago.
I'm writing a console utility to do some processing on files specified on the commandline, but I've run into a problem I can't solve through Google/Stack Overflow. If a full path, including drive letter, is specified, how do I reformat that path to be relative to the current working directory?
There must be something similar to the VirtualPathUtility.MakeRelative function, but if there is, it eludes me.
If you don't mind the slashes being switched, you could [ab]use Uri:
Uri file = new Uri(#"c:\foo\bar\blop\blap.txt");
// Must end in a slash to indicate folder
Uri folder = new Uri(#"c:\foo\bar\");
string relativePath =
Uri.UnescapeDataString(
folder.MakeRelativeUri(file)
.ToString()
.Replace('/', Path.DirectorySeparatorChar)
);
As a function/method:
string GetRelativePath(string filespec, string folder)
{
Uri pathUri = new Uri(filespec);
// Folders must end in a slash
if (!folder.EndsWith(Path.DirectorySeparatorChar.ToString()))
{
folder += Path.DirectorySeparatorChar;
}
Uri folderUri = new Uri(folder);
return Uri.UnescapeDataString(folderUri.MakeRelativeUri(pathUri).ToString().Replace('/', Path.DirectorySeparatorChar));
}
You can use Environment.CurrentDirectory to get the current directory, and FileSystemInfo.FullPath to get the full path to any location. So, fully qualify both the current directory and the file in question, and then check whether the full file name starts with the directory name - if it does, just take the appropriate substring based on the directory name's length.
Here's some sample code:
using System;
using System.IO;
class Program
{
public static void Main(string[] args)
{
string currentDir = Environment.CurrentDirectory;
DirectoryInfo directory = new DirectoryInfo(currentDir);
FileInfo file = new FileInfo(args[0]);
string fullDirectory = directory.FullName;
string fullFile = file.FullName;
if (!fullFile.StartsWith(fullDirectory))
{
Console.WriteLine("Unable to make relative path");
}
else
{
// The +1 is to avoid the directory separator
Console.WriteLine("Relative path: {0}",
fullFile.Substring(fullDirectory.Length+1));
}
}
}
I'm not saying it's the most robust thing in the world (symlinks could probably confuse it) but it's probably okay if this is just a tool you'll be using occasionally.
public string MakeRelativePath(string workingDirectory, string fullPath)
{
string result = string.Empty;
int offset;
// this is the easy case. The file is inside of the working directory.
if( fullPath.StartsWith(workingDirectory) )
{
return fullPath.Substring(workingDirectory.Length + 1);
}
// the hard case has to back out of the working directory
string[] baseDirs = workingDirectory.Split(new char[] { ':', '\\', '/' });
string[] fileDirs = fullPath.Split(new char[] { ':', '\\', '/' });
// if we failed to split (empty strings?) or the drive letter does not match
if( baseDirs.Length <= 0 || fileDirs.Length <= 0 || baseDirs[0] != fileDirs[0] )
{
// can't create a relative path between separate harddrives/partitions.
return fullPath;
}
// skip all leading directories that match
for (offset = 1; offset < baseDirs.Length; offset++)
{
if (baseDirs[offset] != fileDirs[offset])
break;
}
// back out of the working directory
for (int i = 0; i < (baseDirs.Length - offset); i++)
{
result += "..\\";
}
// step into the file path
for (int i = offset; i < fileDirs.Length-1; i++)
{
result += fileDirs[i] + "\\";
}
// append the file
result += fileDirs[fileDirs.Length - 1];
return result;
}
This code is probably not bullet-proof but this is what I came up with. It's a little more robust. It takes two paths and returns path B as relative to path A.
example:
MakeRelativePath("c:\\dev\\foo\\bar", "c:\\dev\\junk\\readme.txt")
//returns: "..\\..\\junk\\readme.txt"
MakeRelativePath("c:\\dev\\foo\\bar", "c:\\dev\\foo\\bar\\docs\\readme.txt")
//returns: "docs\\readme.txt"
Thanks to the other answers here and after some experimentation I've created some very useful extension methods:
public static string GetRelativePathFrom(this FileSystemInfo to, FileSystemInfo from)
{
return from.GetRelativePathTo(to);
}
public static string GetRelativePathTo(this FileSystemInfo from, FileSystemInfo to)
{
Func<FileSystemInfo, string> getPath = fsi =>
{
var d = fsi as DirectoryInfo;
return d == null ? fsi.FullName : d.FullName.TrimEnd('\\') + "\\";
};
var fromPath = getPath(from);
var toPath = getPath(to);
var fromUri = new Uri(fromPath);
var toUri = new Uri(toPath);
var relativeUri = fromUri.MakeRelativeUri(toUri);
var relativePath = Uri.UnescapeDataString(relativeUri.ToString());
return relativePath.Replace('/', Path.DirectorySeparatorChar);
}
Important points:
Use FileInfo and DirectoryInfo as method parameters so there is no ambiguity as to what is being worked with. Uri.MakeRelativeUri expects directories to end with a trailing slash.
DirectoryInfo.FullName doesn't normalize the trailing slash. It outputs whatever path was used in the constructor. This extension method takes care of that for you.
There is also a way to do this with some restrictions. This is the code from the article:
public string RelativePath(string absPath, string relTo)
{
string[] absDirs = absPath.Split('\\');
string[] relDirs = relTo.Split('\\');
// Get the shortest of the two paths
int len = absDirs.Length < relDirs.Length ? absDirs.Length : relDirs.Length;
// Use to determine where in the loop we exited
int lastCommonRoot = -1; int index;
// Find common root
for (index = 0; index < len; index++)
{
if (absDirs[index] == relDirs[index])
lastCommonRoot = index;
else break;
}
// If we didn't find a common prefix then throw
if (lastCommonRoot == -1)
{
throw new ArgumentException("Paths do not have a common base");
}
// Build up the relative path
StringBuilder relativePath = new StringBuilder();
// Add on the ..
for (index = lastCommonRoot + 1; index < absDirs.Length; index++)
{
if (absDirs[index].Length > 0) relativePath.Append("..\\");
}
// Add on the folders
for (index = lastCommonRoot + 1; index < relDirs.Length - 1; index++)
{
relativePath.Append(relDirs[index] + "\\");
}
relativePath.Append(relDirs[relDirs.Length - 1]);
return relativePath.ToString();
}
When executing this piece of code:
string path1 = #"C:\Inetpub\wwwroot\Project1\Master\Dev\SubDir1";
string path2 = #"C:\Inetpub\wwwroot\Project1\Master\Dev\SubDir2\SubDirIWant";
System.Console.WriteLine (RelativePath(path1, path2));
System.Console.WriteLine (RelativePath(path2, path1));
it prints out:
..\SubDir2\SubDirIWant
..\..\SubDir1

Categories