I have an application which read from a file and shows the contents of the file in popups. the text file contain data in such a way;
D:\\abc\\xyz.txt|xyz.txt
D:\\MP3\\boom.mp3|boom.mp3
Now the application reads a line from the text file and shows the line content in another form, and these popups are displayed at once, what i want to do is, if there are multiple lines then each popup is shown after a pause of 10sec, but Thread.Sleep(10000)is not working for me. the code to read is given below.
void FileDetected()
{
int counter = 0,c=1;
string line;
System.IO.StreamReader file = new System.IO.StreamReader(FILEPATH);
while ((line = file.ReadLine()) != null)
{
string[] words = line.Split('|');
c = 1;
path = ""; fileName = "";
foreach (string word in words)
{
if (c == 1)
path = word.Replace(#"\\", #"\");
if (c==2)
fileName = word;
c++;
}
counter++;
if (path != "" && fileName != "")
{
Console.WriteLine("Path :" + path);
Console.WriteLine("FileName: " + fileName);
popup dlg = new popup(path, fileName);
dlg.Show();
//Thread.Sleep(10000);
}
}
kindly guide me.
If you are using .NET 4.5 (or 4.0 with Visual Studio 2012 or newer by downloading Microsoft.Bcl.Async via NuGet) it is very easy to do with async/await.
//You will likely need to modify the calling code to use async/await too.
async Task FileDetected()
{
int counter = 0,c=1;
string line;
System.IO.StreamReader file = new System.IO.StreamReader(FILEPATH);
while ((line = file.ReadLine()) != null)
{
string[] words = line.Split('|');
c = 1;
path = ""; fileName = "";
foreach (string word in words)
{
if (c == 1)
path = word.Replace(#"\\", #"\");
if (c==2)
fileName = word;
c++;
}
counter++;
if (path != "" && fileName != "")
{
Console.WriteLine("Path :" + path);
Console.WriteLine("FileName: " + fileName);
popup dlg = new popup(path, fileName);
dlg.Show();
//Pauses the loop for 10 sec but does not lock up the UI.
await Task.Delay(10000);
}
}
Related
I have an issue with Files.
I am doing an image importer so clients put their files on an FTP server and then they can import it in the application.
During the import process I copy the file in the FTP Folder to another folder with File.copy
public List<Visuel> ImportVisuel(int galerieId, string[] images)
{
Galerie targetGalerie = MemoryCache.GetGaleriById(galerieId);
List<FormatImage> listeFormats = MemoryCache.FormatImageToList();
int i = 0;
List<Visuel> visuelAddList = new List<Visuel>();
List<Visuel> visuelUpdateList = new List<Visuel>();
List<Visuel> returnList = new List<Visuel>();
foreach (string item in images)
{
i++;
Progress.ImportProgress[Progress.Guid] = "Image " + i + " sur " + images.Count() + " importées";
string extension = Path.GetExtension(item);
string fileName = Path.GetFileName(item);
string originalPath = HttpContext.Current.Request.PhysicalApplicationPath + "Uploads\\";
string destinationPath = HttpContext.Current.Server.MapPath("~/Images/Catalogue") + "\\";
Visuel importImage = MemoryCache.GetVisuelByFilName(fileName);
bool update = true;
if (importImage == null) { importImage = new Visuel(); update = false; }
Size imageSize = importImage.GetJpegImageSize(originalPath + fileName);
FormatImage format = listeFormats.Where(f => f.width == imageSize.Width && f.height == imageSize.Height).FirstOrDefault();
string saveFileName = Guid.NewGuid() + extension;
File.Copy(originalPath + fileName, destinationPath + saveFileName);
if (format != null)
{
importImage.format = format;
switch (format.key)
{
case "Catalogue":
importImage.fileName = saveFileName;
importImage.originalFileName = fileName;
importImage.dossier = targetGalerie;
importImage.dossier_id = targetGalerie.id;
importImage.filePath = "Images/Catalogue/";
importImage.largeur = imageSize.Width;
importImage.hauteur = imageSize.Height;
importImage.isRoot = true;
if (update == false) { MemoryCache.Add(ref importImage); returnList.Add(importImage); }
if (update == true) visuelUpdateList.Add(importImage);
foreach (FormatImage f in listeFormats)
{
if (f.key.StartsWith("Catalogue_"))
{
string[] keys = f.key.Split('_');
string destinationFileName = saveFileName.Insert(saveFileName.IndexOf('.'), "-" + keys[1].ToString());
string destinationFileNameDeclinaison = destinationPath + destinationFileName;
VisuelResizer declinaison = new VisuelResizer();
declinaison.Save(originalPath + fileName, f.width, f.height, 1000, destinationFileNameDeclinaison);
Visuel visuel = MemoryCache.GetVisuelByFilName(fileName.Insert(fileName.IndexOf('.'), "-" + keys[1].ToString()));
update = true;
if (visuel == null) { visuel = new Visuel(); update = false; }
visuel.parent = importImage;
visuel.filePath = "Images/Catalogue/";
visuel.fileName = destinationFileName;
visuel.originalFileName = string.Empty;
visuel.format = f;
//visuel.dossier = targetGalerie; On s'en fout pour les déclinaisons
visuel.largeur = f.width;
visuel.hauteur = f.height;
if (update == false)
{
visuelAddList.Add(visuel);
}
else
{
visuelUpdateList.Add(visuel);
}
//importImage.declinaisons.Add(visuel);
}
}
break;
}
}
}
MemoryCache.Add(ref visuelAddList);
// FONCTION à implémenter
MemoryCache.Update(ref visuelUpdateList);
return returnList;
}
After some processes on the copy (the original file is no more used)
the client have a pop-up asking him if he wants to delete the original files in the ftp folder.
If he clicks on Ok another method is called on the same controller
and this method use
public void DeleteImageFile(string[] files)
{
for (int i = 0; i < files.Length; i++)
{
File.Delete(HttpContext.Current.Request.PhysicalApplicationPath + files[i].Replace(#"/", #"\"));
}
}
This method works fine and really delete the good files when I use it in other context.
But here I have an error message:
Process can't acces to file ... because it's used by another process.
Someone have an idea?
Thank you.
Here's the screenshot of Process Explorer
There are couple of thing you can do here.
1) If you can repro it, you can use Process Explorer at that moment and see which process is locking the file and if the process is ur process then making sure that you close the file handle after your work is done.
2) Use try/catch around the delete statement and retry after few seconds to see if the file handle was released.
3) If you can do it offline you can put in some queue and do the deletion on it later on.
You solve this by using c# locks. Just embed your code inside a lock statement and your threads will be safe and wait each other to complete processing.
I found the solution:
in my import method, there a call to that method
public void Save(string originalFile, int maxWidth, int maxHeight, int quality, string filePath)
{
Bitmap image = new Bitmap(originalFile);
Save(ref image, maxWidth, maxHeight, quality, filePath);
}
The bitmap maintains the file opened blocking delete.
just added
image.Dispose();
in the methos and it work fine.
Thank you for your help, and thank you for process explorer. Very useful tool
I have a csv file, and I need to add a unique ID based on the first two characters of the file. I have the following code:
using (StreamReader sr = new StreamReader(f))
{
string currentLine;
int id = 0;
while ((currentLine = sr.ReadLine()) != null)
{
string row = currentLine.ToString();
string FirstTwoCharacters = currentLine.Substring(0, 2);
if (FirstTwoCharacters == "01")
{
id = id + 1;
row += "*" + id.ToString();
using (StreamWriter files = File.AppendText(dir + newfilename))
{
files.WriteLine(row);
}
}
else
{
row += "*" + id.ToString();
using (StreamWriter files = File.AppendText(dir + newfilename))
{
files.WriteLine(row);
}
}
}
}
The csv files can be huge, 1Gb in size, around 6 million rows. Just wanted advice, if there is a quicker way to handling this, as it currently can take 3+ hours to process a file, and multiple files can be received in one go.
Instead of opening new file for appending line for each line of input file you can keep stream writer opened:
using (StreamReader sr = new StreamReader(f))
using (StreamWriter files = File.AppendText(dir + newfilename))
{
string currentLine;
int id = 0;
while ((currentLine = sr.ReadLine()) != null)
{
string firstTwoCharacters = currentLine.Substring(0, 2);
if (firstTwoCharacters == "01")
id++;
files.WriteLine(currentLine + "*" + id);
}
}
You can also use File.ReadLines to enumerate source lines:
using (StreamWriter writer = File.AppendText(dir + newfilename))
{
int id = 0;
foreach(var line in File.ReadLines(f))
{
if (line.Substring(0,2) == "01")
id++;
writer.WriteLine($"{line}*{id}");
}
}
Or even LINQ approach
int id = 0;
var newLines = from line in File.ReadLines(f)
let incrementId = line.Substring(0,2) == "01"
select $"{line}*{incrementId ? (++id) : id}";
File.WriteAllLines(dir + newfilename, newLines);
opening the (File.AppendText) inside the while loop is costly, move this to outside the while
using (StreamReader sr = new StreamReader(f))
{
string currentLine;
int id = 0;
using (StreamWriter files = File.AppendText(dir + newfilename))
{
while ((currentLine = sr.ReadLine()) != null)
{
string row = currentLine.ToString();
string FirstTwoCharacters = currentLine.Substring(0, 2);
if (FirstTwoCharacters == "01")
{
id = id + 1;
row += "*" + id.ToString();
files.WriteLine(row);
}
else
{
row += "*" + id.ToString();
files.WriteLine(row);
}
}
}
}
I am trying to create a program that will replace a string inside .txt file.
heres the trick. I am replacing the string in the file if they are checked,
but when I do an alternate check its still replacing the other.
private void BatchReplace()
{
string sourceFolder = FilePath.Text;
string searchWord = Searchbar.Text;
DateTime now = DateTime.Now;
List<string> allFiles = new List<string>();
AddFileNamesToList(sourceFolder, allFiles);
if (listView1.CheckedItems.Count != 0)
{
foreach (String file in allFiles)
{
for (int x = 0; x <= listView1.CheckedItems.Count - 1; x++)
{
if (file.Contains(listView1.CheckedItems[x].Text))
{
MessageBox.Show("File contains: " + listView1.CheckedItems[x].Text);
try
{
DialogResult dialogResult = MessageBox.Show("Are you sure you want to replace \"" + Searchbar.Text + "\" with \"" + Replacebar.Text + "\"?", "WARNING!", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
StreamReader reader = new StreamReader(file);
string content = reader.ReadToEnd();
reader.Close();
content = Regex.Replace(content, Searchbar.Text, Replacebar.Text);
StreamWriter writer = new StreamWriter(file);
writer.Write(content); writer.Close();
}
else
{
}
}
catch
{
}
}
}
}
}
}
else
{
MessageBox.Show("Please Check the files you want to rename");
}
}
public static void AddFileNamesToList(string sourceDir, List<string> allFiles)
{
string[] fileEntries = Directory.GetFiles(sourceDir);
try
{
foreach (string fileName in fileEntries)
{
allFiles.Add(fileName);
}
//Recursion
string[] subdirectoryEntries = Directory.GetDirectories(sourceDir);
foreach (string item in subdirectoryEntries)
{
// Avoid "reparse points"
if ((File.GetAttributes(item) & FileAttributes.ReparsePoint) != FileAttributes.ReparsePoint)
{
AddFileNamesToList(item, allFiles);
}
}
}
I am still confused about what you are trying to do, but to simplify things, why don't you, when you populate the ListView with the files in the directory, add the file path (or a file object) to the tag property of the ListViewitem?
That way, when you loop through the checked items, you can just retrieve the file directly instead of having to loop through two Lists at once.
Something like:
private void BatchReplace()
{
string sourceFolder = FilePath.Text;
string searchWord = Searchbar.Text;
AddFileNamesToList(sourceFolder);
if (listView1.CheckedItems.Count == 0)
{
MessageBox.Show("Please Check the files you want to rename");
return;
}
for (int x = 0; x < listView1.CheckedItems.Count; x++)
{
var file = listView1.CheckedItems[x].Tag.ToString()
try
{
DialogResult dialogResult = MessageBox.Show("Are you sure you want to replace \"" + Searchbar.Text + "\" with \"" + Replacebar.Text + "\"?", "WARNING!", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
StreamReader reader = new StreamReader(file);
string content = reader.ReadToEnd();
reader.Close();
content = Regex.Replace(content, SearchWord, Replacebar.Text);
StreamWriter writer = new StreamWriter(file);
writer.Write(content);
writer.Close();
}
}
catch
{
}
}
}
}
Sorry for the indenting and also if this doesn't work straight as is, I haven't tested this.
I have a page where I want to upload a CSV file from my computer to database on the server and I have my opentext that looks like the following
using (StreamReader sr = File.OpenText(#"c:\users\workstationUsername\FileName.csv"))
This works fine on my local machine but when I push this to the server it tries to read the server's C Drive and I want it to read the physical file location that is sitting on the desktop of the user's computer not the server, when they click browse and upload..
Thank you
below is the complete code:
if (IsPostBack)
{
// SetDefaultDates();
Boolean fileOK = false;
String dateString = DateTime.Now.ToString("MMddyyyy");
String UserName = User.Identity.Name;
String path = Server.MapPath("~/Uploads/CSVs/");
string stringpath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
String fileName = System.IO.Path.GetFileName(FileUpload1.PostedFile.FileName);
stringpath = stringpath + fileName;
String LocationToSave = path + "\\" + fileName;
if (FileUpload1.HasFile)
{
String fileExtension =
System.IO.Path.GetExtension(FileUpload1.FileName).ToLower();
String[] allowedExtensions = { ".csv" };
for (int i = 0; i < allowedExtensions.Length; i++)
{
if (fileExtension == allowedExtensions[i])
{
fileOK = true;
}
}
}
if (fileOK)
{
try
{
//FileUpload1.PostedFile.SaveAs(LocationToSave + dateString + "-" + FileUpload1.FileName);
FileUpload1.PostedFile.SaveAs(LocationToSave);
Label1.Text = "File " + FileUpload1.FileName + " uploaded!";
DataTable dt = new DataTable();
string line = null;
int i = 0;
using (StreamReader sr = File.OpenText(stringpath))
{
while ((line = sr.ReadLine()) != null)
{
string[] data = line.Split(',');
if (data.Length > 0)
{
if (i == 0)
{
foreach (var item in data)
{
dt.Columns.Add(new DataColumn());
}
i++;
}
DataRow row = dt.NewRow();
row.ItemArray = data;
dt.Rows.Add(row);
}
}
}
using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["Myconnection"].ConnectionString))
{
cn.Open();
using (SqlBulkCopy copy = new SqlBulkCopy(cn))
{
copy.WriteToServer(dt);
}
}
}
catch (Exception ex)
{
Label1.Text = "File " + FileUpload1.FileName + " could not be uploaded." + ex.Message;
}
}
else
{
Label1.Text = "Cannot accept files of this type. " + FileUpload1.FileName;
}
}
SetDefaultDates();
}
If you have a FileUpload control, then instead of using (StreamReader sr = File.OpenText(#"c:\users\workstationUsername\FileName.csv")) which obvously is pointing to the server's hard drive you can do this:
(StreamReader sr = new StreamReader(fileUploadControl.FileContent))
//Do your stuff
You can't access the client's hard drive. That's a major security concern. You'll need to upload the file to your server, and read it from there.
It doesnt make sense to have a static read to the local machine, rather get user to upload it then update the database, this code is very limiting and has a high security risk. Rather create a steamreader object get the user to upload it then use the steam reader to process the csv.
I am currently using CKEditor for my project to read and display the content of a html file.
However, instead of getting the content of the file, all I get is a string: < html > display in the editor.
But if I write the content directly to the page using response.write, then all the content of the file is displayed correctly.
this is the code snippet I used to read the file:
strPathToConvert = Server.MapPath("~/convert/");
object filetosave = strPathToConvert + "paper.htm";
StreamReader reader = new StreamReader(filetosave.ToString());
string content = "";
while ((content = reader.ReadLine()) != null)
{
if ((content == "") || (content == " "))
{ continue; }
CKEditor1.Text = content;
//Response.Write(content);
}
Can anybody help me to solve this problem?
Many Thanks.
You are in a while loop and you are overwriting the contents of CKEditor every time since you use = instead of +=. Your loops should be:
StreamReader reader = new StreamReader(filetosave.ToString());
string content = "";
while ((content = reader.ReadLine()) != null)
{
if ((content == "") || (content == " "))
{ continue; }
CKEditor1.Text += content;
//Response.Write(content);
}
a better way would probably be to use
string content;
string line;
using (StreamReader reader = new StreamReader(filetosave.ToString())
{
while ((line= reader.ReadLine()) != null)
{
content += line;
}
}
CKEditor1.Text = content;