public void Convert_Xls_To_CSV(string sourceFile, string targetFile)
{
try
{
// wrtr = new StreamWriter(targetFile);
StreamWriter wrtr = new StreamWriter(new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.Read));
DataTable dt = ConvertExcelFileToDataTable(sourceFile);
for (int x = 0; x < dt.Rows.Count; x++)
{
string rowString = "";
for (int y = 0; y < dt.Columns.Count; y++)
{
rowString += "\"" + dt.Rows[x][y].ToString() + "\",";
}
wrtr.WriteLine(rowString);
}
wrtr.Close();
wrtr.Dispose();
}
catch (Exception ex)
{
Error_lb.Text = ex.Message;
}
}
I'm using this function to write a csvfile.the targetFile is not created.
StreamWriter wrtr = new StreamWriter(new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.Read));
should this line create the file if it's not exist ?
Simplify your call to;
sw = new StreamWriter(fileNameToSave, false)
From MSDN;
StreamWriter(String, Boolean) - Initializes a new instance of the StreamWriter class for the specified file by using the default encoding and buffer size. If the file exists, it can be either overwritten or appended to. If the file does not exist, this constructor creates a new file.
Also, your usage seems similar to something I have some code for;
var saveFile = new SaveFileDialog();
saveFile.InitialDirectory = Properties.Settings.Default.systemLogPath;
saveFile.RestoreDirectory = true;
saveFile.Title = "Filename to log to";
saveFile.Filter = "Text (*.txt)|*.txt|Log (*.log)|*.log";
if (saveFile.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
using (var sw = new StreamWriter(saveFile.FileName, false))
{
foreach (var item in messages.Items)
{
sw.Write(item.ToString() + Environment.NewLine);
}
}
}
Maybe that can be of use to you as well.
Please read the documentation.
Your second parameter refers to the FileMode Enumeration which says the following about FileMode.Create:
Specifies that the operating system should create a new file. If the file already exists, it will be overwritten.
Related
We have a problem where our industrial equipments software's .XML settings files become blank, yet they still have the correct number of bytes.
I have a feeling it might be caused by the way the customers are shutting down the PC as it tends to happen after they've down a shutdown, isolate, and boot. The way I save the files is,
Serialize to %temp% file
Validate that the newly created file starts with <?xml
If the /backup folders version of the file is older than a day, copy the existing file to the /backup folder
Copy new file to overwrite existing file.
I thought maybe it's related to encoding, disk caching, Windows Update, or Windows Recovery.
Looking for ideas as I've spent two years chasing down why this is happening.
As per request, here is the code.
public static bool SerializeObjXml(object Object2Serialize, string FilePath, Type type, bool gzip = false)
{
if (!Path.IsPathRooted(FilePath))
FilePath = Path.Combine(ApplicationDir, FilePath);
bool isSuccess = false;
var tmpFile = Path.GetTempFileName();
try
{
for (int i = 0; i < 3; i++)
{
try
{
Directory.CreateDirectory(Path.GetDirectoryName(FilePath));
if (gzip)
{
using (var ms = new MemoryStream())
{
XmlSerializer bf = new XmlSerializer(type);
bf.Serialize(ms, Object2Serialize);
ms.Position = 0;
using (var fileStream = new BinaryWriter(File.Open(tmpFile, FileMode.Create)))
{
using (GZipStream gzipStream = new GZipStream(fileStream.BaseStream, CompressionMode.Compress))
{
byte[] buffer = new byte[4096];
int numRead;
while ((numRead = ms.Read(buffer, 0, buffer.Length)) != 0)
{
gzipStream.Write(buffer, 0, numRead);
}
}
}
}
if (!FileChecker.isGZip(tmpFile))
throw new XmlException("Failed to write valid XML file " + FilePath);
}
else
{
using (var fs = new StreamWriter(File.Open(tmpFile, FileMode.Create), Encoding.UTF8))
{
XmlSerializer bf = new XmlSerializer(type);
bf.Serialize(fs, Object2Serialize);
}
if (!FileChecker.isXML(tmpFile))
throw new XmlException("Failed to write valid XML file " + FilePath);
}
isSuccess = true;
return true;
}
catch (XmlException)
{
return false;
}
catch (System.IO.DriveNotFoundException) { continue; }
catch (System.IO.DirectoryNotFoundException) { continue; }
catch (System.IO.FileNotFoundException) { continue; }
catch (System.IO.IOException) { continue; }
}
}
finally
{
if (isSuccess)
{
lock (FilePath)
{
try
{
//Delete existing .bak file
if (File.Exists(FilePath + ".bak"))
{
File.SetAttributes(FilePath + ".bak", FileAttributes.Normal);
File.Delete(FilePath + ".bak");
}
}
catch { }
try
{
//Make copy of file as .bak
if (File.Exists(FilePath))
{
File.SetAttributes(FilePath, FileAttributes.Normal);
File.Copy(FilePath, FilePath + ".bak", true);
}
}
catch { }
try
{
//Copy the temp file to the target
File.Copy(tmpFile, FilePath, true);
//Delete .bak file if no error
if (File.Exists(FilePath + ".bak"))
File.Delete(FilePath + ".bak");
}
catch { }
}
}
try
{
//Delete the %temp% file
if (File.Exists(tmpFile))
File.Delete(tmpFile);
}
catch { }
}
return false;
}
public static class FileChecker
{
const string gzipSig = "1F-8B-08";
static string xmlSig = "EF-BB-BF";// <?x";
public static bool isGZip(string filepath)
{
return FileChecker.CheckSignature(filepath, (3, gzipSig)) != null;
}
public static bool isXML(string filepath)
{
return FileChecker.CheckSignature(filepath, (3, xmlSig)) != null;
}
public static bool isGZipOrXML(string filepath, out bool isGZip, out bool isXML)
{
var sig = FileChecker.CheckSignature(filepath, (3, gzipSig), (3, xmlSig));
isXML = (sig == xmlSig);
isGZip = (sig == gzipSig);
return isXML || isGZip;
}
public static string CheckSignature(string filepath, params (int signatureSize, string expectedSignature)[] pairs)
{
if (String.IsNullOrEmpty(filepath))
throw new ArgumentException("Must specify a filepath");
if (String.IsNullOrEmpty(pairs[0].expectedSignature))
throw new ArgumentException("Must specify a value for the expected file signature");
int signatureSize = 0;
foreach (var pair in pairs)
if (pair.signatureSize > signatureSize)
signatureSize = pair.signatureSize;
using (FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
if (fs.Length < signatureSize)
return null;
byte[] signature = new byte[signatureSize];
int bytesRequired = signatureSize;
int index = 0;
while (bytesRequired > 0)
{
int bytesRead = fs.Read(signature, index, bytesRequired);
bytesRequired -= bytesRead;
index += bytesRead;
}
foreach (var pair in pairs)
{
string actualSignature = BitConverter.ToString(signature, 0, pair.signatureSize);
if (actualSignature == pair.expectedSignature)
return actualSignature;
}
}
return null;
}
}
Using the operating system's move or copy file to overwrite an existing file is an atomic operation meaning the it wholly succeeds or doesn't and doesn't overlap other file operations.
Therefore what you have should work if that is how you are achieving step 4.
Copy new file to overwrite existing file.
If instead you are blanking out the existing file and re-writing the data I suspect that could be the the point of failure..
The issues while file space is being allocated the write is not occurring during shutdown, which leaves you when a file with bytes allocated without the data being flushed to disk.
During the OS shutdown, likely a ThreadAbortException is raised which triggers your finally block.
You can attempt to reproduce by calling Process.Start("shutdown", "-a") before your return statement but after you have set success = true.
I would suggest simplifying your code and have everything run inside of your try {} statement. This removes the possibility of having a state where success = true before your attempted your write to disk, which is then triggered in a finally statement trigged by a windows shutdown.
public static bool SerializeObjXml(
object Object2Serialize,
string FilePath,
Type type,
bool gzip = false)
{
if (!Path.IsPathRooted(FilePath))
FilePath = Path.Combine(ApplicationDir, FilePath);
Directory.CreateDirectory(FilePath);
for (int i = 0; i < 3; i++)
{
try
{
var tempFi = SerializeToXmlFile(Object2Serialize, type, gzip);
var fi = new FileInfo(FilePath);
if (fi.Exists)
fi.CopyTo(fi.FullName + ".bak", true);
tempFi.CopyTo(fi.FullName, true);
tempFi.Delete();
return true;
}
catch (Exception ex)
{
string message = $"[{DateTime.Now}] Error serializing file {FilePath}. {ex}";
File.WriteAllText(FilePath + ".log", message);
}
}
return false;
}
As a side note, you can simply use [Stream.CopyTo][1] and write directly to your temp file, without the need for intermediary streams or for manual buffer/byte read/write operations:
private static FileInfo SerializeToXmlFile(
object Object2Serialize,
Type type,
bool gzip)
{
var tmpFile = Path.GetTempFileName();
var tempFi = new FileInfo(tmpFile);
if (!gzip)
{
using (var fs = File.Open(tmpFile, FileMode.Create))
(new XmlSerializer(type)).Serialize(fs, Object2Serialize);
if (!FileChecker.isXML(tmpFile))
throw new Exception($"Failed to write valid XML file: {tmpFile}");
}
else
{
using (var fs = File.Open(tmpFile, FileMode.CreateNew))
using (var gz = new GZipStream(fs, CompressionMode.Compress))
(new XmlSerializer(type)).Serialize(fs, Object2Serialize);
if (!FileChecker.isGZip(tmpFile))
throw new Exception($"Failed to write valid XML gz file: {tmpFile}");
}
return tempFi;
}
I want to open a text file, append a single line to it, then close it.
You can use File.AppendAllText for that:
File.AppendAllText(#"c:\path\file.txt", "text content" + Environment.NewLine);
using (StreamWriter w = File.AppendText("myFile.txt"))
{
w.WriteLine("hello");
}
Choice one! But the first is very simple. The last maybe util for file manipulation:
//Method 1 (I like this)
File.AppendAllLines(
"FileAppendAllLines.txt",
new string[] { "line1", "line2", "line3" });
//Method 2
File.AppendAllText(
"FileAppendAllText.txt",
"line1" + Environment.NewLine +
"line2" + Environment.NewLine +
"line3" + Environment.NewLine);
//Method 3
using (StreamWriter stream = File.AppendText("FileAppendText.txt"))
{
stream.WriteLine("line1");
stream.WriteLine("line2");
stream.WriteLine("line3");
}
//Method 4
using (StreamWriter stream = new StreamWriter("StreamWriter.txt", true))
{
stream.WriteLine("line1");
stream.WriteLine("line2");
stream.WriteLine("line3");
}
//Method 5
using (StreamWriter stream = new FileInfo("FileInfo.txt").AppendText())
{
stream.WriteLine("line1");
stream.WriteLine("line2");
stream.WriteLine("line3");
}
Or you could use File.AppendAllLines(string, IEnumerable<string>)
File.AppendAllLines(#"C:\Path\file.txt", new[] { "my text content" });
Might want to check out the TextWriter class.
//Open File
TextWriter tw = new StreamWriter("file.txt");
//Write to file
tw.WriteLine("test info");
//Close File
tw.Close();
The technically best way is probably this here:
private static async Task AppendLineToFileAsync([NotNull] string path, string line)
{
if (string.IsNullOrWhiteSpace(path))
throw new ArgumentOutOfRangeException(nameof(path), path, "Was null or whitepsace.");
if (!File.Exists(path))
throw new FileNotFoundException("File not found.", nameof(path));
using (var file = File.Open(path, FileMode.Append, FileAccess.Write))
using (var writer = new StreamWriter(file))
{
await writer.WriteLineAsync(line);
await writer.FlushAsync();
}
}
File.AppendText will do it:
using (StreamWriter w = File.AppendText("textFile.txt"))
{
w.WriteLine ("-------HURRAY----------");
w.Flush();
}
//display sample reg form in notepad.txt
using (StreamWriter stream = new FileInfo("D:\\tt.txt").AppendText())//ur file location//.AppendText())
{
stream.WriteLine("Name :" + textBox1.Text);//display textbox data in notepad
stream.WriteLine("DOB : " + dateTimePicker1.Text);//display datepicker data in notepad
stream.WriteLine("DEP:" + comboBox1.SelectedItem.ToString());
stream.WriteLine("EXM :" + listBox1.SelectedItem.ToString());
}
We can use
public StreamWriter(string path, bool append);
while opening the file
string path="C:\\MyFolder\\Notes.txt"
StreamWriter writer = new StreamWriter(path, true);
First parameter is a string to hold a full file path
Second parameter is Append Mode, that in this case is made true
Writing to the file can be done with:
writer.Write(string)
or
writer.WriteLine(string)
Sample Code
private void WriteAndAppend()
{
string Path = Application.StartupPath + "\\notes.txt";
FileInfo fi = new FileInfo(Path);
StreamWriter SW;
StreamReader SR;
if (fi.Exists)
{
SR = new StreamReader(Path);
string Line = "";
while (!SR.EndOfStream) // Till the last line
{
Line = SR.ReadLine();
}
SR.Close();
int x = 0;
if (Line.Trim().Length <= 0)
{
x = 0;
}
else
{
x = Convert.ToInt32(Line.Substring(0, Line.IndexOf('.')));
}
x++;
SW = new StreamWriter(Path, true);
SW.WriteLine("-----"+string.Format("{0:dd-MMM-yyyy hh:mm:ss tt}", DateTime.Now));
SW.WriteLine(x.ToString() + "." + textBox1.Text);
}
else
{
SW = new StreamWriter(Path);
SW.WriteLine("-----" + string.Format("{0:dd-MMM-yyyy hh:mm:ss tt}", DateTime.Now));
SW.WriteLine("1." + textBox1.Text);
}
SW.Flush();
SW.Close();
}
I have created a program which cleans access and error logs and then outputs them in a new file in the same directory. The input is in format .txt and the output is in format .csv - however it is giving me two output files, one in .csv format and one in .txt format(.txt file is empty) instead of just the .csv file? I can't understand why this is happening.
Below is the two ouput files as shown in the directory:
Below is the code which generates the new file with the unique name:
static FileStream CreateFileWithUniqueName(string folder, string fileName, int maxAttempts = 1024)
{
var fileBase = Path.GetFileNameWithoutExtension(fileName);
var ext = Path.GetExtension(fileName);
// build hash set of filenames for performance
var files = new HashSet<string> (Directory.GetFiles(folder));
for (var index = 0; index < maxAttempts; index++)
{
// first try with the original filename, else try incrementally adding an index
var name = (index == 0)
? fileName
: String.Format("{0} ({1}){2}", fileBase, index, ext);
// check if exists
var fullPath = Path.Combine(folder, name);
if(files.Contains(fullPath))
continue;
// try to create the file
try
{
return new FileStream(fullPath, FileMode.CreateNew, FileAccess.Write);
}
catch (DirectoryNotFoundException) { throw; }
catch (DriveNotFoundException) { throw; }
catch (IOException)
{
}
}
throw new Exception("Could not create unique filename in " + maxAttempts + " attempts");
}
And finally the code below is the code which reads in the existing file and cleans it:
public static void readFile(string fileName)
{
using (var stream = CreateFileWithUniqueName(#"C:\Users\michael\Desktop\WindowsFormsApplication1\WindowsFormsApplication1\bin\Debug\", fileName))
{
Console.WriteLine("Created \"" + stream.Name + "\"");
newFileName = stream.Name;
Globals.CleanedErrorFileName = newFileName;
}
string CSVfileName = Path.ChangeExtension(newFileName, ".csv");
StreamReader reader = new StreamReader(fileName);
StreamWriter writer = new StreamWriter(CSVfileName);
string line;
string personalIdentifier = new string(fileName.Take(4).ToArray());
string gender = fileName.Substring(fileName.Length - 5, 1);
string classification = fileName.Substring(fileName.Length - 8, 2);
string text = string.Empty;
while ((line = reader.ReadLine()) != null)
{
string[] cleanArray;
cleanArray = new string[5];
var result = line.Split('[')
.Select((element, index) => index % 2 == 0
? element.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
: new string[] { element })
.SelectMany(element => element).ToList();
cleanArray[0] = personalIdentifier;
cleanArray[1] = gender;
cleanArray[2] = classification;
cleanArray[3] = result[0];
cleanArray[4] = result[2];
cleanArray[4] = cleanArray[4].Substring(7);
cleanArray[4] = cleanArray[4].Replace("]", " ");
cleanArray[4] = cleanArray[4].Insert(15, ",");
cleanArray[3] = cleanArray[3].Remove(cleanArray[3].Length - 2);
cleanArray[4] = cleanArray[4].Substring(0, cleanArray[4].IndexOf(":") + 1);
//re-formatting the date so that it can be accepted by machine learning
var dateString = cleanArray[3];
var date = DateTime.ParseExact(dateString, "ddd MMM dd HH:mm:ss yyyy", CultureInfo.InvariantCulture);
var newDateString = date.ToString("yyyy-MM-dd HH:mm:ss");
//inserting the new date and time into the array
cleanArray[3] = newDateString;
//push each clean array onto the file that has been automatically created at the top
writer.WriteLine(string.Join(", ", cleanArray.Select(v => v.ToString())));
writer.WriteLine();
}
I'm hoping the issue is something small but i can't seem to find it!
Thanks in advance!!
This line is the culprit:
return new FileStream(fullPath, FileMode.CreateNew, FileAccess.Write);
At this point, the file name in fullPath still has .txt extension, this creates the empty .txt file. Then you change extension to .csv and do this:
StreamWriter writer = new StreamWriter(CSVfileName);
which creates the new .csv file
Also, both streams are never closed in your code.
I am having the hardest time figuring out how to do this.
I have a listbox with a lot of data in it. I want to take this listbox and then have a button to save it.
The button will choose the directory to put the files in. Afterwards, the program should start saving these values into a text file with the naming schema Seed1.txt, Seed2.txt, etc.
The thing is, I would like to put only 100 items into each text file that is generated until the list is done.
For saving the path I have:
Stream s;
string folderPath = string.Empty;
using (FolderBrowserDialog fdb = new FolderBrowserDialog())
{
if (fdb.ShowDialog() == DialogResult.OK)
{
folderPath = fdb.SelectedPath;
MessageBox.Show(folderPath);
}
For saving everything in one shot, I believe this will work:
int total = list_failed.Items.Count;
for (int i = 0; i < list_failed.Items.Count; i++)
{
StreamWriter text = new StreamWriter(s);
text.Write(list_failed.Items[i]);
s.Close();
I'm not sure about the rest though. Something like this for the filenames perhaps
string filename;
int i = 0;
do
{
filename = "Seed" + ++i + ".txt";
} while (files.Contains(filename));
Here's a working example that you can use.
string pathname = Server.MapPath("/");
int counter = 1;
string file = String.Empty;
List<string> list = new List<string>();
//Add the list items
for (int i = 0; i <= 1234; i++)
{
list.Add(String.Format("item {0}", i));
}
//write to file
for (int i = 1; i < list.Count(); i++)
{
//generate a dynamic filename with path
file = String.Format("{0}Seed{1}.txt", pathname, counter);
//the using statement closes the streamwriter when it completes the process
using (StreamWriter text = new StreamWriter(file, true))
{
//write the line
text.Write(list[i]);
}
//check to see if the max lines have been written
if (i == counter * 100) counter++;
}
string folderPath;
const int ITEMS_PER_FILE=100;
void AskUserForFolder()
{
folderPath = string.Empty;
using (FolderBrowserDialog fdb = new FolderBrowserDialog())
{
if (fdb.ShowDialog() == DialogResult.OK)
{
folderPath = fdb.SelectedPath;
// MessageBox.Show(folderPath);
}
}
}
void SaveItems(ListBox listBox, int seed)
{
int total = listBox.Items.Count;
for ( int fileCount=0;fileCount<listBox.Items.Count/ITEMS_PER_FILE;++fileCount)
{
using (StreamWriter sw = new StreamWriter(folderPath + "\\" + GetFilePath(folderPath, "filename.txt",ref seed)))
{
for (int i = 0; i < listBox.Items.Count; i++)
{
sw.WriteLine(listBox.Items[i+(ITEMS_PER_FILE*fileCount)]);
}
sw.Close();
}
}
}
//I'm not sure about the rest though. Something like this for the filenames perhaps
/// <summary>
/// Gets a filename that has not been used before by incrementing a number at the end of the filename
/// </summary>
/// <param name="seed">seed is passed in as a referrect value and acts as a starting point to itterate through the list
/// By passing it in as a reference we can save ourselves from having to itterate unneccssarily for the start each time
/// </param>
/// <returns>the path of the file</returns>
string GetFilePath(string folderpath, string fileName,string extension,ref int seed)
{
FileInfo fi = new FileInfo(string.Format("{0}\\{1}{2}.{3}", folderPath, fileName, seed,extension));
while (fi.Exists)
{
fi = new FileInfo(string.Format("{0}\\{1}{2}.{3}", folderPath, fileName, ++seed,extension));
}
return fi.FullName;
}
Try this to iterate over ListBox items and put them in files with up to 100 items:
private void writeItemsToFile(ListBox lb)
{
string path = #"c:\test\";
string filename = "seed";
int itemCounter = 0;
int fileCounter = 1;
StreamWriter sw = new StreamWriter(File.OpenWrite(System.IO.Path.Combine(path,string.Format(filename+"{0}.txt",fileCounter))));
foreach (var s in lb.Items)
{
if (itemCounter > 100)
{
fileCounter++;
itemCounter = 0;
sw.Flush();
sw.Close();
sw.Dispose();
sw = null;
sw = new StreamWriter(File.OpenWrite(System.IO.Path.Combine(path,string.Format(filename+"{0}.txt",fileCounter))));
}
sw.WriteLine(s.ToString());
itemCounter++;
}
if (sw != null)
{
sw.Flush();
sw.Dispose();
}
}
Well i'm trying to merge multiple PDFs in to one.
I gives no errors while compiling. I tried to merge the docs first but that went wrong because I'm working with tables.
This is the asp.net code-behind
if (Button.Equals("PreviewWord")) {
String eventTemplate = Server.MapPath("/ERAS/Badges/Template/EventTemp" + EventName + ".doc");
String SinglePreview = Server.MapPath("/ERAS/Badges/Template/PreviewSingle" + EventName + ".doc");
String PDFPreview = Server.MapPath("/ERAS/Badges/Template/PDFPreviewSingle" + EventName + ".pdf");
String previewPDFs = Server.MapPath("/ERAS/Badges/Template/PreviewPDFs" + EventName + ".pdf");
if (System.IO.File.Exists((String)eventTemplate))
{
if (vulGegevensIn == true)
{
//This creates a Worddocument and fills in names etc from database
CreateWordDocument(vulGegevensIn, eventTemplate, SinglePreview, false);
//This saves the SinglePreview.doc as a PDF #param place of PDFPreview
CreatePDF(SinglePreview, PDFPreview);
//Trying to merge
String[] previewsSmall=new String[1];
previewsSmall[0] = PDFPreview;
PDFMergenITextSharp.MergeFiles(previewPDFs, previewsSmall);
}
// merge PDFs here...........................;
//here
//no here//
//...
} }
This is the PDFMergenITextSharpClass
public static class PDFMergenITextSharp
{
public static void MergeFiles(string destinationFile, string[] sourceFiles)
{
try
{
int f = 0;
// we create a reader for a certain document
PdfReader reader = new PdfReader(sourceFiles[f]);
// we retrieve the total number of pages
int n = reader.NumberOfPages;
//Console.WriteLine("There are " + n + " pages in the original file.");
// step 1: creation of a document-object
Document document = new Document(reader.GetPageSizeWithRotation(1));
// step 2: we create a writer that listens to the document
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(destinationFile, FileMode.Create));
// step 3: we open the document
document.Open();
PdfContentByte cb = writer.DirectContent;
PdfImportedPage page;
int rotation;
// step 4: we add content
while (f < sourceFiles.Length)
{
int i = 0;
while (i < n)
{
i++;
document.SetPageSize(reader.GetPageSizeWithRotation(i));
document.NewPage();
page = writer.GetImportedPage(reader, i);
rotation = reader.GetPageRotation(i);
if (rotation == 90 || rotation == 270)
{
cb.AddTemplate(page, 0, -1f, 1f, 0, 0, reader.GetPageSizeWithRotation(i).Height);
}
else
{
cb.AddTemplate(page, 1f, 0, 0, 1f, 0, 0);
}
//Console.WriteLine("Processed page " + i);
}
f++;
if (f < sourceFiles.Length)
{
reader = new PdfReader(sourceFiles[f]);
// we retrieve the total number of pages
n = reader.NumberOfPages;
//Console.WriteLine("There are " + n + " pages in the original file.");
}
}
// step 5: we close the document
document.Close();
}
catch (Exception e)
{
string strOb = e.Message;
}
}
public static int CountPageNo(string strFileName)
{
// we create a reader for a certain document
PdfReader reader = new PdfReader(strFileName);
// we retrieve the total number of pages
return reader.NumberOfPages;
}
}
I found the answer:
Instead of the 2nd Method, add more files to the first array of input files.
public static void CombineMultiplePDFs(string[] fileNames, string outFile)
{
// step 1: creation of a document-object
Document document = new Document();
//create newFileStream object which will be disposed at the end
using (FileStream newFileStream = new FileStream(outFile, FileMode.Create))
{
// step 2: we create a writer that listens to the document
PdfCopy writer = new PdfCopy(document, newFileStream);
// step 3: we open the document
document.Open();
foreach (string fileName in fileNames)
{
// we create a reader for a certain document
PdfReader reader = new PdfReader(fileName);
reader.ConsolidateNamedDestinations();
// step 4: we add content
for (int i = 1; i <= reader.NumberOfPages; i++)
{
PdfImportedPage page = writer.GetImportedPage(reader, i);
writer.AddPage(page);
}
PRAcroForm form = reader.AcroForm;
if (form != null)
{
writer.CopyAcroForm(reader);
}
reader.Close();
}
// step 5: we close the document and writer
writer.Close();
document.Close();
}//disposes the newFileStream object
}
I found a very nice solution on this site : http://weblogs.sqlteam.com/mladenp/archive/2014/01/10/simple-merging-of-pdf-documents-with-itextsharp-5-4-5.aspx
I update the method in this mode :
public static bool MergePdfs(IEnumerable<string> fileNames, string targetFileName)
{
bool success = true;
using (FileStream stream = new(targetFileName, FileMode.Create))
{
Document document = new();
PdfCopy pdf = new(document, stream);
PdfReader? reader = null;
try
{
document.Open();
foreach (string file in fileNames)
{
reader = new PdfReader(file);
pdf.AddDocument(reader);
reader.Close();
}
}
catch (Exception)
{
success = false;
reader?.Close();
}
finally
{
document?.Close();
}
}
return success;
}
Code For Merging PDF's in Itextsharp
public static void Merge(List<String> InFiles, String OutFile)
{
using (FileStream stream = new FileStream(OutFile, FileMode.Create))
using (Document doc = new Document())
using (PdfCopy pdf = new PdfCopy(doc, stream))
{
doc.Open();
PdfReader reader = null;
PdfImportedPage page = null;
//fixed typo
InFiles.ForEach(file =>
{
reader = new PdfReader(file);
for (int i = 0; i < reader.NumberOfPages; i++)
{
page = pdf.GetImportedPage(reader, i + 1);
pdf.AddPage(page);
}
pdf.FreeReader(reader);
reader.Close();
File.Delete(file);
});
}
}
Using iTextSharp.dll
protected void Page_Load(object sender, EventArgs e)
{
String[] files = #"C:\ENROLLDOCS\A1.pdf,C:\ENROLLDOCS\A2.pdf".Split(',');
MergeFiles(#"C:\ENROLLDOCS\New1.pdf", files);
}
public void MergeFiles(string destinationFile, string[] sourceFiles)
{
if (System.IO.File.Exists(destinationFile))
System.IO.File.Delete(destinationFile);
string[] sSrcFile;
sSrcFile = new string[2];
string[] arr = new string[2];
for (int i = 0; i <= sourceFiles.Length - 1; i++)
{
if (sourceFiles[i] != null)
{
if (sourceFiles[i].Trim() != "")
arr[i] = sourceFiles[i].ToString();
}
}
if (arr != null)
{
sSrcFile = new string[2];
for (int ic = 0; ic <= arr.Length - 1; ic++)
{
sSrcFile[ic] = arr[ic].ToString();
}
}
try
{
int f = 0;
PdfReader reader = new PdfReader(sSrcFile[f]);
int n = reader.NumberOfPages;
Response.Write("There are " + n + " pages in the original file.");
Document document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(destinationFile, FileMode.Create));
document.Open();
PdfContentByte cb = writer.DirectContent;
PdfImportedPage page;
int rotation;
while (f < sSrcFile.Length)
{
int i = 0;
while (i < n)
{
i++;
document.SetPageSize(PageSize.A4);
document.NewPage();
page = writer.GetImportedPage(reader, i);
rotation = reader.GetPageRotation(i);
if (rotation == 90 || rotation == 270)
{
cb.AddTemplate(page, 0, -1f, 1f, 0, 0, reader.GetPageSizeWithRotation(i).Height);
}
else
{
cb.AddTemplate(page, 1f, 0, 0, 1f, 0, 0);
}
Response.Write("\n Processed page " + i);
}
f++;
if (f < sSrcFile.Length)
{
reader = new PdfReader(sSrcFile[f]);
n = reader.NumberOfPages;
Response.Write("There are " + n + " pages in the original file.");
}
}
Response.Write("Success");
document.Close();
}
catch (Exception e)
{
Response.Write(e.Message);
}
}
Merge byte arrays of multiple PDF files:
public static byte[] MergePDFs(List<byte[]> pdfFiles)
{
if (pdfFiles.Count > 1)
{
PdfReader finalPdf;
Document pdfContainer;
PdfWriter pdfCopy;
MemoryStream msFinalPdf = new MemoryStream();
finalPdf = new PdfReader(pdfFiles[0]);
pdfContainer = new Document();
pdfCopy = new PdfSmartCopy(pdfContainer, msFinalPdf);
pdfContainer.Open();
for (int k = 0; k < pdfFiles.Count; k++)
{
finalPdf = new PdfReader(pdfFiles[k]);
for (int i = 1; i < finalPdf.NumberOfPages + 1; i++)
{
((PdfSmartCopy)pdfCopy).AddPage(pdfCopy.GetImportedPage(finalPdf, i));
}
pdfCopy.FreeReader(finalPdf);
}
finalPdf.Close();
pdfCopy.Close();
pdfContainer.Close();
return msFinalPdf.ToArray();
}
else if (pdfFiles.Count == 1)
{
return pdfFiles[0];
}
return null;
}
I don't see this solution anywhere and supposedly ... according to one person, the proper way to do it is with copyPagesTo(). This does work I tested it. Your mileage may vary between city and open road driving. Goo luck.
public static bool MergePDFs(List<string> lststrInputFiles, string OutputFile, out int iPageCount, out string strError)
{
strError = string.Empty;
PdfWriter pdfWriter = new PdfWriter(OutputFile);
PdfDocument pdfDocumentOut = new PdfDocument(pdfWriter);
PdfReader pdfReader0 = new PdfReader(lststrInputFiles[0]);
PdfDocument pdfDocument0 = new PdfDocument(pdfReader0);
int iFirstPdfPageCount0 = pdfDocument0.GetNumberOfPages();
pdfDocument0.CopyPagesTo(1, iFirstPdfPageCount0, pdfDocumentOut);
iPageCount = pdfDocumentOut.GetNumberOfPages();
for (int ii = 1; ii < lststrInputFiles.Count; ii++)
{
PdfReader pdfReader1 = new PdfReader(lststrInputFiles[ii]);
PdfDocument pdfDocument1 = new PdfDocument(pdfReader1);
int iFirstPdfPageCount1 = pdfDocument1.GetNumberOfPages();
iPageCount += iFirstPdfPageCount1;
pdfDocument1.CopyPagesTo(1, iFirstPdfPageCount1, pdfDocumentOut);
int iFirstPdfPageCount00 = pdfDocumentOut.GetNumberOfPages();
}
pdfDocumentOut.Close();
return true;
}
Please also visit and read this article where I explained everything in detail about How to Merge Multiple PDF Files Into Single PDF Using Itextsharp in C#
Implementation:
try
{
string FPath = "";
// Create For loop for get/create muliple report on single click based on row of gridview control
for (int j = 0; j < Gridview1.Rows.Count; j++)
{
// Return datatable for data
DataTable dtDetail = new My_GlobalClass().GetDataTable(Convert.ToInt32(Gridview1.Rows[0]["JobId"]));
int i = Convert.ToInt32(Gridview1.Rows[0]["JobId"]);
if (dtDetail.Rows.Count > 0)
{
// Create Object of ReportDocument
ReportDocument cryRpt = new ReportDocument();
//Store path of .rpt file
string StrPath = Application.StartupPath + "\\RPT";
StrPath = StrPath + "\\";
StrPath = StrPath + "rptCodingvila_Articles_Report.rpt";
cryRpt.Load(StrPath);
// Assign Report Datasource
cryRpt.SetDataSource(dtDetail);
// Assign Reportsource to Report viewer
CryViewer.ReportSource = cryRpt;
CryViewer.Refresh();
// Store path/name of pdf file one by one
string StrPathN = Application.StartupPath + "\\Temp" + "\\Codingvila_Articles_Report" + i.ToString() + ".Pdf";
FPath = FPath == "" ? StrPathN : FPath + "," + StrPathN;
// Export Report in PDF
cryRpt.ExportToDisk(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat, StrPathN);
}
}
if (FPath != "")
{
// Check for File Existing or Not
if (System.IO.File.Exists(Application.StartupPath + "\\Temp" + "\\Codingvila_Articles_Report.pdf"))
System.IO.File.Delete(Application.StartupPath + "\\Temp" + "\\Codingvila_Articles_Report.pdf");
// Split and store pdf input file
string[] files = FPath.Split(',');
// Marge Multiple PDF File
MargeMultiplePDF(files, Application.StartupPath + "\\Temp" + "\\Codingvila_Articles_Report.pdf");
// Open Created/Marged PDF Output File
Process.Start(Application.StartupPath + "\\Temp" + "\\Codingvila_Articles_Report.pdf");
// Check and Delete Input file
foreach (string item in files)
{
if (System.IO.File.Exists(item.ToString()))
System.IO.File.Delete(item.ToString());
}
}
}
catch (Exception ex)
{
XtraMessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Create Function for Marge PDF
public static void MargeMultiplePDF(string[] PDFfileNames, string OutputFile)
{
iTextSharp.text.Document PDFdoc = new iTextSharp.text.Document();
using (System.IO.FileStream MyFileStream = new System.IO.FileStream(OutputFile, System.IO.FileMode.Create))
{
iTextSharp.text.pdf.PdfCopy PDFwriter = new iTextSharp.text.pdf.PdfCopy(PDFdoc, MyFileStream);
if (PDFwriter == null)
{
return;
}
PDFdoc.Open();
foreach (string fileName in PDFfileNames)
{
iTextSharp.text.pdf.PdfReader PDFreader = new iTextSharp.text.pdf.PdfReader(fileName);
PDFreader.ConsolidateNamedDestinations();
for (int i = 1; i <= PDFreader.NumberOfPages; i++)
{
iTextSharp.text.pdf.PdfImportedPage page = PDFwriter.GetImportedPage(PDFreader, i);
PDFwriter.AddPage(page);
}
iTextSharp.text.pdf.PRAcroForm form = PDFreader.AcroForm;
if (form != null)
{
PDFwriter.CopyAcroForm(PDFreader);
}
PDFreader.Close();
}
PDFwriter.Close();
PDFdoc.Close();
}
}