C# - Copy File to new location, then read in PDF (With Code) - c#

In the code below, the console prompts the user for 2 files (currently in a networked location). It then copies those files to the local drive for quicker reading of the PDF, but I'm running into a problem. If I reference the last line of code as PdfDocument pdf = new PdfDocument("C:\somepdf.pdf"); the file is accessed extremely quickly.
However, with the current copy processes, for some reason, this line of code alone is taking upwards of 18-20 minutes to process. I'm assuming that this is because the file, having recently been copied, is still locked under a process, even though the actual copy process takes less than 10 seconds.
In my research, I have seen various ways of identifying the process that's locking the file and killing it, but this doesn't seem to apply to what I'm trying to do.
Unfortunately, I'm to the point where I have to ask for help. Am I overlooking something here? I don't see why it would take 15 less minutes to process a pdf referenced locally, than one processed by a copy process, then locally.
Thoughts?
string selectFileNameO;
string selectFileNameF;
string FileNameO;
string FileNameF;
using (OpenFileDialog dialog = new OpenFileDialog())
{
dialog.Title = "Choose File";
dialog.FileName = "";
dialog.ShowDialog();
selectFileNameO = dialog.FileName;
}
string ext = System.IO.Path.GetExtension(selectFileNameO);
selectFileNameF = Path.GetFileName(selectFileNameO);
selectFileNameF = selectFileNameF.Substring(0, selectFileNameF.Length - ext.Length);
selectFileNameF = "C:\\" + selectFileNameF + ".ext";
Console.WriteLine(selectFileNameF);
using (OpenFileDialog dialog2 = new OpenFileDialog())
{
dialog2.Title = "Choose 2 File";
dialog2.FileName = "";
dialog2.ShowDialog();
FileNameO = dialog2.FileName;
}
string ext1 = System.IO.Path.GetExtension(FileNameO);
FileNameF = Path.GetFileName(FileNameO);
FileNameF = FileNameF.Substring(0, FileNameF.Length - ext1.Length);
FileNameF = "C:\\" + FileNameF + ".ext";
File.Copy(FileNameO, FileNameF, true);
int distanceToString = 535;
int lengthOfString = 6;
string myDataSet;
using (StreamReader sr = new StreamReader(selectFileNameF))
{
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
myDataSet = line.Substring(distanceToString, lengthOfString);
selectFileUIDs.Add(myDataSet);
Console.WriteLine(myDataSet);
}
sr.Dispose();
}
Console.WriteLine(FileNameF);
PdfDocument pdf = new PdfDocument(FileNameF);

Related

GUI Reading from CSV

I have been working on converting a GUI script from another language to C# using VS2017. I have the whole thing working for the most part, but have come on a problem. The gui has a listview which I am populating either manually through entering data in various fields or as an import from a CSV. The manual entry works just fine. The CSV import works as well, however it is pulling the header line into the listview. Here is the code I am using for the button to kick off the import:
private void import(object sender, RoutedEventArgs e)
{
OpenFileDialog xls = new OpenFileDialog();
xls.Multiselect = false;
xls.Filter = "CSV files (*.csv)|*.csv";
xls.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
xls.ShowDialog();
string ins;
if (xls.FileName != null)
{
FileStream srcFS;
srcFS = new FileStream(xls.FileName, FileMode.Open);
StreamReader srcSR = new StreamReader(srcFS, System.Text.Encoding.Default);
do
{
ins = srcSR.ReadLine();
if (ins != null)
{
string[] parts = ins.Split(',');
MyItems.Add(new MyItem
{
Name = parts[0],
CPU = parts[1],
RAM = parts[2],
IP = parts[3],
Subnet = parts[4],
PortGroup = parts[5],
Gateway = parts[6],
DNS = parts[7],
Description = parts[8],
Template = parts[9],
Host = parts[10],
Site = parts[11],
Folder = parts[12],
Datastore = parts[13],
Patch = parts[14],
HDD1_Size = parts[15],
HDD2_Size = parts[16],
HDD3_Size = parts[17],
HDD4_Size = parts[18],
HDD5_Size = parts[19],
HDD6_Size = parts[20],
HDD7_Size = parts[21],
HDD8_Size = parts[22],
HDD9_Size = parts[23],
HDD10_Size = parts[24]
});
}
} while (ins != null);
srcSR.Close();
}
}
I have been googling for some ways to skip the first line, but it most of the suggestions have been to iterate through line by line and write the lines one at a time, which slows the import process (there could be hundreds of lines). Just curious if there is a simple way to tell the StreamReader where to begin reading the file.
You want to read a line and throw it away. Just add an ins = srcSR.ReadLine(); right above your do.

JSON string values are getting saved without quotes

I have two programs. The first program creates some JSON using Json.Net and then launches the second program, passing the JSON to it. The second program saves the JSON to a file using the SaveFileDialog from WinForms. The problem is the string values in the JSON are not saving properly.
For example, it saves
{
projectName : MY_PROJECT_NAME
}
When it should be
{
"projectName" : "MY_PROJECT_NAME"
}
Later when I'm trying to deserialize the JSON and convert to an object, I'm getting an error, but only with string values.
Here is the code that saves the file:
[STAThread]
static void Main(string[] args)
{
string seriaizedData = args[0];
Stream streamData;
SaveFileDialog savefiledialog = new SaveFileDialog();
savefiledialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/Bamboo Wall";
savefiledialog.Filter = "bamboo files (*.bamboo)|*.bamboo|All files (*.*)|*.*";
savefiledialog.FilterIndex = 1;
savefiledialog.RestoreDirectory = true;
if (savefiledialog.ShowDialog() == DialogResult.OK)
{
if ((streamData = savefiledialog.OpenFile()) != null)
{
byte[] buffer = Encoding.ASCII.GetBytes(seriaizedData);
streamData.Write(buffer, 0, buffer.Length);
streamData.Close();
}
}
}
Here is the code that creates the JSON:
FloorModel grdData = GridData.gridData.gridDataClassList[GetActiveTabIndex()];
//How I get the object does not matter so much
string jsonObj = JsonConvert.SerializeObject(grdData);
print (jsonObj);
Process myProcess = new Process();
myProcess.StartInfo.FileName = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "Narnia.exe";
myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
myProcess.StartInfo.Arguments = jsonObj;
myProcess.Start();
What am I doing wrong?
The problem is that you are passing JSON on the command line from one program to the other. Quote characters and spaces have special meaning to the command line parser, so you will need escape your JSON string judiciously if you want it to survive the command line parsing process intact. Another potential issue is the command line has a length limit, depending on what platform you are running on. So if the JSON you are trying to pass is large, it may be truncated even if you manage to escape it correctly. In short, I don't recommend this approach.
Instead, I would make your first program write the JSON to a temporary file, then pass the path of the temp file to the second program via the command line. That program can then copy the file to the correct location as specified by the user.
So, something like this:
Sending Program
FloorModel grdData = GridData.gridData.gridDataClassList[GetActiveTabIndex()];
string json = JsonConvert.SerializeObject(grdData);
string tempFile = Path.GetTempFileName();
File.WriteAllText(tempFile, json);
Process myProcess = new Process();
myProcess.StartInfo.FileName = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "Narnia.exe";
myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
myProcess.StartInfo.Arguments = '"' + tempFile + '"';
myProcess.Start();
Receiving Program
string jsonTempFile = args[0];
try
{
SaveFileDialog savefiledialog = new SaveFileDialog();
savefiledialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/Bamboo Wall";
savefiledialog.Filter = "bamboo files (*.bamboo)|*.bamboo|All files (*.*)|*.*";
savefiledialog.FilterIndex = 1;
savefiledialog.RestoreDirectory = true;
if (savefiledialog.ShowDialog() == DialogResult.OK)
{
File.Copy(jsonTempFile, savefiledialog.FileName, overwrite: true);
}
}
finally
{
File.Delete(jsonTempFile);
}

create textfile dynamically if textfile size exceeds maximum size

I'm writing text to files using StreamWriter using the following code:
path == #"Desktop\";
filepath1 = path + "1.txt";
StreamWriter _sw = new StreamWriter(filepath1, true);
_sw.WriteLine("some Text");
_sw.Close();
if size of textfile exceeds 500kb I want to create text files dynamically. I'm tryng following code:
var size = (path.Length)/1024;
if(size>=500)
{
int i = (size/500)+1;
var filepath2 = path + i + ".txt";
if (File.Exists(filepath2))
{
StreamWriter _sw = new StreamWriter(filepath2, true);
_sw.WriteLine("Some message");
_sw.Close();
}
}
else
{
FileStream fs = File.Create(filepath2);
StreamWriter _sw = new StreamWriter(filepath2, true);
_sw.WriteLine(ex);
_sw.Close();
}
My question is if file 2.txt also exceeds 500kb I want to create 3.txt,4.txt..... and so on..
I want to create all these dynamically - how to solve this problem?
First thing you need to do the SIZE comparison for the data length of File not the File Path.
Here is Function which dose what you want to achieve, Please make appropriate changes for your path.
//Public variable to manage file names
int FileCounter = 1;
string FileName;
// Call this function to Add text to file
private void WriteToFile(string writeText)
{
FileName = "MyFile_"+FileCounter +".txt";
if (File.Exists(FileName))
{
string str = File.ReadAllText(FileName);
if ((str.Length + writeText.Length) / 1024 > 500) // check for limit
{
// Create new File
FileCounter++;
FileName = "MyFile_" + FileCounter + ".txt";
StreamWriter _sw = new StreamWriter(FileName, true);
_sw.WriteLine(writeText);
_sw.Close();
}
else // use exixting file
{
StreamWriter _sw = new StreamWriter(FileName, true);
_sw.WriteLine(writeText);
_sw.Close();
}
}
}
Where to start..
You are writing it as one big long procedural script. You need to break it down into chunks that can be reused using functions. As it is, it will get out of control way too quickly.
path == #"Desktop\"; is not valid. 1 too many =
Use Path.Combine() to combine your folder and filenames.
I'm sure this is all just test/rough/scratch code but just in case it's not, also check out Try/Except to wrap your file handling. You should also look up using() to dispose of your streams/writers.
My last comment would be that I see a lot of this sort of code a lot and it's often replaceable with something like Nlog for a whole lot less friction.
I would have commented but this login has no rep.

How to get the name of a folder on a website

I'm looking for a way for me to get the folder name which is located on (for example) http://example.com/download/"foldername here"
The reason for this is because I have a c# program which always downloads a .zip if you don't allready have it, but currently it won't download a new version.
Example: Currently it downloads from http://example.com/download/1.0/file.zip, if you allready have the folder it checks for, it won't download it, but if you do have that folder, it won't download from http://example.com/download/2.0/file.zip, which contains the new version. I have made a file which contains the current version, but how can I get my program to check that file against the folder in which the newest version resides?
Edit: I reworked my code so it downloads a version.txt file first and reads it contents, which contains the latest version of the download.
Code:
if (radUseFile.Checked)
{
//get latest version on website
WebClient modver = new WebClient();
modver.UseDefaultCredentials = true;
modver.DownloadFile("http://www.example.com/download/version.txt", tempdir _
+ "version.txt");
using (StreamReader ver = new StreamReader(tempdir + "version.txt"))
{
siteversion = ver.ReadToEnd();
}
File.Delete(tempdir + "version.txt");
if (Directory.Exists(folder))
{
if (File.Exists(folder + "\\version.txt"))
{
using (StreamReader sr = new StreamReader(folder + "\\version.txt"))
{
latestversion = sr.ReadToEnd();
}
if (latestversion != siteversion)
{
uptodate = false;
}
else
{
uptodate = true;
}
}
}
else
{
uptodate = false;
}
if (!uptodate)
{
//download and extract the files
WebClient downloader = new WebClient();
label4.Text = "Downloading full client. May take a while";
this.Update();
downloader.UseDefaultCredentials = true;
downloader.DownloadFile("http://www.example.com/download" + siteversion _
+ "/zipfile.zip", templocation + "zipfile.zip");
label4.Text = "Extracting...";
Shell32.Shell sc = new Shell32.Shell();
Directory.CreateDirectory(tempdir);
Shell32.Folder output = sc.NameSpace(tempdir);
Shell32.Folder input = sc.NameSpace(tempdir + "zipfile.zip");
output.CopyHere(input.Items(), 4);
label4.Text = "Cleaning up...";
File.Delete(tempdir + "zipfile.zip");
new Microsoft.VisualBasic.Devices.Computer().FileSystem.CopyDirectory(tempdir,_
folderlocation, true);
Directory.Delete(tempdir, true);
uptodate = true;
}
}
else
{
uptodate = true;
}
This works for now, but I'm pretty sure this code can be improved, or the entire method as to how it takes the latest version
You could have a text file, containing the latest version number and where to download it from, in a permanent location, say http://example.com/download/latestversion.txt. Then use WebClient.DownloadString to retrieve that file, and take the appropriate action depending on the content of the file.

Not able to print a document

One of the methods i used :
PrintDocument doc = new PrintDocument();
doc.PrinterSettings.PrinterName = "printername";
string[] files = Directory.GetFiles("D:\\Invoice");
foreach (string file in files)
{
string fname = Path.GetFileName(file);
doc.DocumentName = fname;
doc.Print();
Console.WriteLine(file);
}
This gives an exception on the doc.Print() line.
"Settings to access printer 'printername' are not valid."
The other method i used :
Process printJob = new Process();
printJob.StartInfo.FileName = #"C:\Program Files (x86)\Adobe\Reader 10.0\Reader\AcroRD32.exe";
printJob.StartInfo.UseShellExecute = false;
printJob.StartInfo.Verb = "Print";
printJob.StartInfo.CreateNoWindow = true;
printJob.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
printJob.StartInfo.Arguments = "\"" + printerAddress + "\"";
string[] files = Directory.GetFiles("D:\\Invoice");
foreach (string file in files)
{
string fname = Path.GetFileName(file);
printJob.StartInfo.WorkingDirectory = Path.GetDirectoryName(fname);
printJob.Start();
//Console.WriteLine(fname);
}
This gives an error after printJob.Start(). As it is pdf file, it opens the Adobe reader and displays the error message there. Hopw it explains.
"There was an error opening the document. The file could not be found."
Can anyone help me on these issues?
In 2nd snippet, this seems wrong:
string fname = Path.GetFileName(file);
printJob.StartInfo.WorkingDirectory = Path.GetDirectoryName(fname);
printJob.Start();
You just set WorkingDirectory. How does printJob get the actual file name?
In 1st snippet, you are probably not setting everything. Have you checked the MSDN documentation? It's generally a good idea to try to find, then read and try to understand the docs, before asking at SO...

Categories

Resources