I'm using DotNetZip library to make multi-file zip archive and download it on the fly (no need to wait for download to start). However I can't make it to download instantly. From browser dev console, in network tab I noticed that first zip file is "transferred" and after being fully transferred it starts downloading.
Here is code fragment:
using (var vZipArchive = new ZipFile())
{
if (vFilesTable.Rows.Count > 0)
{
string vPathFormat = null;
string vKeyName = null;
string vPrimKey = null;
string vFileName = null;
vZipArchive.CompressionLevel = CompressionLevel.BestSpeed;
vZipArchive.CompressionMethod = CompressionMethod.Deflate;
vZipArchive.Comment = "Document Archive";
foreach (DataRow vFile in vFilesTable.Rows)
{
if (vKeyFieldName != null && !string.IsNullOrEmpty(vKeyFieldName))
{
vPathFormat = "{0}/";
}
else
{
vPathFormat = "/";
}
if (vFile.Table.Columns.Contains("FileName") && vFile.Table.Columns.Contains("PrimKey"))
{
vPrimKey = vFile["PrimKey"].ToString();
vFileName = vFile["FileName"].ToString();
if (vKeyFieldName != null)
{
vKeyName = vFile[vKeyFieldName].ToString();
}
string vPath = null;
if (vKeyFieldName != null)
{
vPath = string.Format(vKeyFieldName + " " + vPathFormat + "{1}", vKeyName, vFileName);
}
else
{
vPath = string.Format(vPathFormat + vFileName);
}
using (var vFileStream = vUserContext.GetFileStream(vRecordSource.ViewName, new Guid(vPrimKey)))
{
vFileStream.Position = 0;
vZipArchive.AddEntry(vPath, vFileStream);
}
}
else
{
throw new Exception("Select 'FileName' and 'PrimKey' fields in underlying DataSource");
}
} //end loop
pContext.Response.Clear();
pContext.Response.BufferOutput = false;
pContext.Response.ContentType = "application/zip";
pContext.Response.AddHeader("Content-Disposition", string.Format("attachment; filename=\"{0}.zip\"", vZipName));
vZipArchive.Save(pContext.Response.OutputStream);
}
else
{
return;
}
}
I also tried using ZipOutputStream and SharpCompress.dll library.
So, what I am missing to make it work? Or its impossible?
Related
When I am saving an image, it is getting saved by the Barcode name.
But If I modify the barcode name, then the image is gone, not saving.
I have noticed while debugging that the if(System.IO.File.Exists(imageFilePath)) is not executing when I am updating the barcode. But at the time of saving a new one, its executing.
How to correct this?
Updating code
public object Update(ItemEntity item)
{
var val = _itemRepository.Save(item);
if (item.ImageFileName != string.Empty || item.ImageOriginalFileName != string.Empty)
{
string result = JsonConvert.SerializeObject(val);
var definition = new { Success = false, EntryMode = string.Empty, BarCode = string.Empty, ItemCode = string.Empty };
var info = JsonConvert.DeserializeAnonymousType(result, definition);
if (info.Success)
{
if (!string.IsNullOrEmpty(item.ImageOriginalFileName))
this.SaveImage(item.ImageFileName, (item.ImageOriginalFileName == "BARCODE" ? info.ItemCode : item.ImageOriginalFileName == "BARCODEYes" ? item.Barcode : item.ImageOriginalFileName));
}
}
if (item.DeleteImageFileName != string.Empty && item.ImageFileName == string.Empty) // Image file removed but no new image file is uploaded[Bug Id :34754 -No image is uploaded, when a user re-uploads an image after deleting a previous one.]
{
this.DeleteImage(item.DeleteImageFileName);
}
return val;
}
Saving Code
public void SaveImage(string fileName, string originalFileName)
{
string tempFileName = fileName;
if (!string.IsNullOrEmpty(tempFileName))
{
// move file from temp location to actual loation
var webAppPath = System.Web.Hosting.HostingEnvironment.MapPath("~");
var splitPath = webAppPath.Split("\\".ToCharArray()).ToList();
var upLevel = splitPath.Count - 1; // one level up
splitPath = splitPath.Take(upLevel).ToList();
var UIFolder = "WebUI";
splitPath.AddRange(new string[] { UIFolder, "Temp", "ImageUpload", CurrentSession.UserId.Value.ToString(), "ItemImage" });
var webUIPath = splitPath.Aggregate((i, j) => i + "\\" + j);
var imageFilePath = Path.Combine(webUIPath.EnsureEndsWith('\\'), tempFileName);
if (System.IO.File.Exists(imageFilePath))
{
splitPath = webAppPath.Split("\\".ToCharArray()).ToList();
upLevel = splitPath.Count - 1; // one level up
splitPath = splitPath.Take(upLevel).ToList();
splitPath.AddRange(new string[] { "Shared", "ItemImage" });
webUIPath = splitPath.Aggregate((i, j) => i + "\\" + j);
// Check existence of folder, create if not found and Delete-Create if found
if (!Directory.Exists(webUIPath))
{
Logger.Debug("Create directory :" + webUIPath);
Directory.CreateDirectory(webUIPath);
}
originalFileName = originalFileName + ".jpg";
var imagDestPath = Path.Combine(webUIPath.EnsureEndsWith('\\'), originalFileName);
if (File.Exists(imagDestPath))
{
GC.Collect();
GC.WaitForPendingFinalizers();
Logger.Debug("Delete File :" + imagDestPath);
File.Delete(imagDestPath);
}
byte[] bytes = System.IO.File.ReadAllBytes(imageFilePath);
FileStream fs = new FileStream(imagDestPath, FileMode.Create, FileAccess.Write);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(bytes);
bw.Close();
}
}
}
So, the html data I'm looking at is:
Action.log<br> 6/8/2015 3:45 PM
From this I need to extract either instances of Action.log,
My problem is I've been over a ton of regex tutorials and I still can't seem to brain up a pattern to extract it. I guess I'm lacking some fundamental understanding of regex, but any help would be appreciated.
Edit:
internal string[] ParseFolderIndex_Alpha(string url, WebDirectory directory)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = 3 * 60 * 1000;
request.KeepAlive = true;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
List<string> fileLocations = new List<string>(); string line;
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
while ((line = reader.ReadLine()) != null)
{
int index = line.IndexOf("<a href=");
if (index >= 0)
{
string[] segments = line.Substring(index).Split('\"');
///Can Parse File Size Here: Add todo
if (!segments[1].Contains("/"))
{
fileLocations.Add(segments[1]);
UI.UpdatePatchNotes("Web File Found: " + segments[1]);
UI.UpdateProgressBar();
}
else
{
if (segments[1] != #"../")
{
directory.SubDirectories.Add(new WebDirectory(url + segments[1], this));
UI.UpdatePatchNotes("Web Directory Found: " + segments[1].Replace("/", string.Empty));
}
}
}
else if (line.Contains("</pre")) break;
}
}
response.Dispose(); /// After ((line = reader.ReadLine()) != null)
return fileLocations.ToArray<string>();
}
else return new string[0]; /// !(HttpStatusCode.OK)
}
catch (Exception e)
{
LogHandler.LogErrors(e.ToString(), this);
LogHandler.LogErrors(url, this);
return null;
}
}
That's what I was doing, the problem is I changed servers and the html IIS is displaying is different so I have to make new logic.
Edit / Conclusion:
First of all, I'm sorry I even mentions regex :P Secondly each platform will have to be handled individually depending on environment.
This is how I'm currently gathering the file names.
internal string[] ParseFolderIndex(string url, WebDirectory directory)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = 3 * 60 * 1000;
request.KeepAlive = true;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
bool endMet = false;
if (response.StatusCode == HttpStatusCode.OK)
{
List<string> fileLocations = new List<string>(); string line;
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
while (!endMet)
{
line = reader.ReadLine();
if (line != null && line != "" && line.IndexOf("</A>") >= 0)
{
if (line.Contains("</html>")) endMet = true;
string[] segments = line.Replace("\\", "").Split('\"');
List<string> paths = new List<string>();
List<string> files = new List<string>();
for (int i = 0; i < segments.Length; i++)
{
if (!segments[i].Contains('<'))
paths.Add(segments[i]);
}
paths.RemoveAt(0);
foreach (String s in paths)
{
string[] secondarySegments = s.Split('/');
if (s.Contains(".") || s.Contains("Verinfo"))
files.Add(secondarySegments[secondarySegments.Length - 1]);
else
{
directory.SubDirectories.Add(new WebDirectory
(url + "/" + secondarySegments[secondarySegments.Length - 2], this));
UI.UpdatePatchNotes("Web Directory Found: " + secondarySegments[secondarySegments.Length - 2]);
}
}
foreach (String s in files)
{
if (!String.IsNullOrEmpty(s) && !s.Contains('%'))
{
fileLocations.Add(s);
UI.UpdatePatchNotes("Web File Found: " + s);
UI.UpdateProgressBar();
}
}
if (line.Contains("</pre")) break;
}
}
}
response.Dispose(); /// After ((line = reader.ReadLine()) != null)
return fileLocations.ToArray<string>();
}
else return new string[0]; /// !(HttpStatusCode.OK)
}
catch (Exception e)
{
LogHandler.LogErrors(e.ToString(), this);
LogHandler.LogErrors(url, this);
return null;
}
}
Regex for this is overkill.
It's too heavy, and considering the format of the string will always be the same, you're going to find it easier to debug and maintain using splitting and substrings.
class Program {
static void Main(string[] args) {
String s = "Action.log<br> 6/8/2015 3:45 PM ";
String[] t = s.Split('"');
String fileName = String.Empty;
//To get the entire file name and path....
fileName = t[1].Substring(0, (t[1].Length));
//To get just the file name (Action.log in this case)....
fileName = t[1].Substring(0, (t[1].Length)).Split('/').Last();
}
}
Try matching the following pattern:
<A HREF="(?<url>.*)">
Then get the group called url from the match results.
Working example: https://regex101.com/r/hW8iH6/1
string text = #"Action.log<br> 6/8/2015 3:45 PM";
var match = Regex.Match(text, #"^(.*).*$");
var result = match.Groups[1].Value;
Try http://regexr.com/ or Regexbuddy!
I am not getting an error but my files are not getting uploaded. Am trying to upload to a targetDirectory on SFTP.
public string TryUploads(string targetDirectory)
{
string _localDirectory = LocalDirectory; //The directory in SFTP server where the files are present
if (oSftp == null)
{
oSftp = Instance;
}
lock (thisLock)
{
try
{
oSftp.Connect();
List<string> fileList = Directory.GetFiles(_localDirectory, "*.*").ToList<string>();
oSftp.ChangeDirectory(targetDirectory);
if (fileList != null && fileList.Count() > 1)
{
for (int i = 0; i < fileList.Count(); i++)
{
string ftpFileName = Path.GetFileName(fileList[i]);
if (!String.IsNullOrEmpty(targetDirectory))
ftpFileName = String.Format("{0}/{1}", targetDirectory, ftpFileName);
using (var stream = new FileStream(Path.GetFileName(fileList[i]), FileMode.Create))
{
oSftp.BufferSize = 4 * 1024;
oSftp.UploadFile(stream, ftpFileName);
// stream.Close();
}
}
}
oSftp.Disconnect();
}
catch (Exception e)
{
throw new ApplicationException(e.Message);
}
}
return Strings.StatusOk;
}
I solved the issue. I needed to put the location of where am getting the file from in the stream
using (var stream = new FileStream(LocalDirectory + "\\" + Path.GetFileName(fileList[i]), FileMode.Open))
Solved. Files uploaded ;)
I am working with a project where I am generating PDF Files from PSR Files. The PDF Files works fine if its a single page but if It has more than two PSR Files and I generate two files it does not open on iPad and works fine on Desktop.
The Third library tool I am using here is 'dbatuotrack' and I am using C#.
Can anyone please guide me how to resolve this problem?
Thanks,
S.
foreach (var pdfform in pdfPagesID)
{
//dbAutoTrack.PDFWriter.Document objDoc = null;
//dbAutoTrack.PDFWriter.Page objPage = null;
objDoc = new dbAutoTrack.PDFWriter.Document();
pdfPagesID.Clear();
pdfPagesID = GetSpecPageID(pdfform);
if (pdfPagesID.Count > 1)
{
foreach (var pdfPage in pdfPagesID)
{
dbAutoTrack.PDFWriter.Page objPage2 = null;
var lastItem = pdfPagesID.Last();
prefixPageID = prefixSpecPageID(pdfPage);
suffixPageIDPSR = prefixPageID + ".psr";
if (File.Exists(PSRPath + suffixPageIDPSR))
{
objDs = new CDatasheet(this.PSRPath + suffixPageIDPSR, false);
objDs.pdfDbHelper = pdfhelper;
//Giving the specformId as SpecFornName
pdfFormName = "Form" + pdfform + ".pdf";
if (!(pdfPage == pdfPagesID.First()))
{
objPage2 = objDs.Generate_PDFReport();
objDoc.Pages.Add(objPage2);
}
else
{
objPage = objDs.Generate_PDFReport();
objDoc.Pages.Add(objPage);
}
if (objPage != null)
{
if (pdfWithNotePage == true && pdfPage.Equals(lastItem))
{
objNotePage = objDs.GetNotePage();
objDoc.Pages.Add(objPage);
objDoc.Pages.Add(objNotePage);
}
else
{
//objDoc.Pages.Add(objPage);
//objDoc.Pages.Add(objPage2);
}
fsOutput = new FileStream(TemplatePath + pdfFormName, FileMode.Create, FileAccess.Write);
objDoc.Generate(fsOutput);
}
if (fsOutput != null)
{
fsOutput.Close();
fsOutput.Dispose();
fsOutput = null;
}
}
}
objDoc = null;
objPage = null;
}
This how I tweaked the code to make it work. Thanks for the suggestion DJ KRAZE
foreach (var pdfform in pdfPagesID)
{
//dbAutoTrack.PDFWriter.Document objDoc = null;
//dbAutoTrack.PDFWriter.Page objPage = null;
objDoc = new dbAutoTrack.PDFWriter.Document();
pdfPagesID.Clear();
pdfPagesID = GetSpecPageID(pdfform);
if (pdfPagesID.Count > 1)
{
foreach (var pdfPage in pdfPagesID)
{
dbAutoTrack.PDFWriter.Page objPage2 = null;
var lastItem = pdfPagesID.Last();
prefixPageID = prefixSpecPageID(pdfPage);
suffixPageIDPSR = prefixPageID + ".psr";
if (File.Exists(PSRPath + suffixPageIDPSR))
{
objDs = new CDatasheet(this.PSRPath + suffixPageIDPSR, false);
objDs.pdfDbHelper = pdfhelper;
//Giving the specformId as SpecFornName
pdfFormName = "Form" + pdfform + ".pdf";
if (!(pdfPage == pdfPagesID.First()))
{
objPage2 = objDs.Generate_PDFReport();
objDoc.Pages.Add(objPage2);
}
else
{
objPage = objDs.Generate_PDFReport();
objDoc.Pages.Add(objPage);
}
if (objPage != null)
{
if (pdfWithNotePage == true && pdfPage.Equals(lastItem))
{
objNotePage = objDs.GetNotePage();
objDoc.Pages.Add(objPage);
objDoc.Pages.Add(objNotePage);
}
else
{
//objDoc.Pages.Add(objPage);
//objDoc.Pages.Add(objPage2);
}
}
}
}
fsOutput = new FileStream(TemplatePath + pdfFormName, FileMode.Create, FileAccess.Write);
objDoc.Generate(fsOutput);
//This region was the problem, disposing the output everytime.
//Needed it to be included after completion of iteration
if (fsOutput != null)
{
fsOutput.Close();
fsOutput.Dispose();
fsOutput = null;
}
}
I am trying to upload a file in asp.net. File may be image or pdf. If the file already exist then I have to remove existing file and upload the new file. But if I try to delete existing file, it shows an error that "The process cannot access the file because it is being used by another process"
This is the code for my file upload.
if (FileUploadFollowUpUN.HasFile)
{
if (Request.QueryString.Count > 0 && Request.QueryString["PCD"] != null)
{
filename = System.IO.Path.GetFileName(FileUploadFollowUpUN.FileName.Replace(FileUploadFollowUpUN.FileName, Request.QueryString["PCD"] + " " + "D" + Path.GetExtension(FileUploadFollowUpUN.FileName)));
SaveFilePath = Server.MapPath("~\\ECG\\") + filename;
DirectoryInfo oDirectoryInfo = new DirectoryInfo(Server.MapPath("~\\ECG\\"));
if (!oDirectoryInfo.Exists)
Directory.CreateDirectory(Server.MapPath("~\\ECG\\"));
if (File.Exists(SaveFilePath))
{
File.SetAttributes(SaveFilePath, FileAttributes.Normal);
File.Delete(SaveFilePath);
}
FileUploadFollowUpUN.SaveAs(Server.MapPath(this.UploadFolderPath) + filename);
Session["FileNameFollowUpUN"] = filename;
if (System.IO.Path.GetExtension(FileUploadFollowUpUN.FileName) == ".pdf")
{
imgPhoto.ImageUrl = "~/Images/pdf.jpg";
ZoomImage.ImageUrl = "~/Images/pdf.jpg";
imgPhoto.Enabled = true;
}
else
{
imgPhoto.ImageUrl = "~/ECG/" + filename;
imgPhoto.Enabled = true;
ZoomImage.ImageUrl = "~/ECG/" + filename;
}
}
}
How can I get rid out of this error?
There is a similar question here on how to find what process is using a file
You should try to dispose any file methods before trying to delete.
You could stick it in a while loop if you have something which will block until the file is accessible
public static bool IsFileReady(String sFilename)
{
// If the file can be opened for exclusive access it means that the file
// is no longer locked by another process.
try
{
using (FileStream inputStream = File.Open(sFilename, FileMode.Open, FileAccess.Read, FileShare.None))
{
if (inputStream.Length > 0)
{
return true;
}
else
{
return false;
}
}
}
catch (Exception)
{
return false;
}
}