Select uploaded files by key - c#

In an ASP.NET application I want to process uploaded files. The HttpContext.Current.Request.Files.AllKeys contains the following:
[0]File2
[1]File2
[2]flTeklif
[3]flTeklif
[4]flTeklif
[5]flTeklif
How can I select only the uploaded files that have key flTeklif into a List<HttpPostedFile>?
I tried this:
var uploads = HttpContext.Current.Request.Files.AllKeys
.Where(s=>s.stringname == "flTeklif")
But that only selects the keys, not the files. How can I select the Files.Where(key == "flTeklif")?

HttpRequest.Files is an HttpFileCollection, whose AllKeys property is a string array.
So you can just use AllKeys.Where(s => s == "flTeklif").
So far for the literal interpretation of your question, which is probably why you're pretty heavily down- and closevoted as it doesn't really make any sense.
If your actual question is "How can I select the files that have flTeklif as their key", use:
var files = HttpContext.Current.Request.Files;
var result = new List<HttpPostedFile>();
for (int i = 0; i < files.AllKeys.Count; i++)
{
if (files.AllKeys[i] == "flTeklif")
{
result.Add(files.AllKeys[i]);
}
}
Then result will contain the files you're interested in.

OK i understand. may be
HttpContext.Current.Request.Files.Cast<HttpPostedFile>().Where(c => c.FileName.Contains("flTeklif")).ToList();

Use HttpFileCollection.GetKey(Int32) method. There is no mention that AllKeys array order is the similiar to the files HttpFileCollection.
int i;
HttpFileCollection MyFileColl = Request.Files;
for( i= 0; i< MyFileColl.Count; i++)
{
if( MyFileColl.GetKey(i) == "flTeklif")
{
//...
}
}

You can use the following code to get a list of all uploaded files against a particular key
HttpFileCollection files = null;
try { files = HttpContext.Current.Request.Files; } catch { }
var allUploadedFilesAgainstThisKey = files.GetMultiple(singleKey); // singleKey is a string
// allUploadedFilesAgainstThisKey is of type IList<HttpPostedFile>

Related

How to check if a string is in an array

I am trying to check whether a string is in an array and if continues even though the fileInfo.Name.Contains a string that is in files.Any:
\\FILES LIKE DATABASE.MDB IS IN C:PROJECTS\HOLON\DATABASE.MDB
**if (files.Any((fileInfo.Name.Contains)))**
\\DO SOMETHING
Console.WriteLine(
fileInfo.Name, fileInfo.Length,
If you alread have the filenames collected in an array, then you should either do it this way:
if (files.Any() && files.Contains(fileInfo.Name))
{
// Do something
}
If you just want to check if a file exists then you can use File.Exists:
if(System.IO.File.Exists(fileInfo.Name))
{
// Do Something
}
So you have a collection of full file paths? And you want to check if one or more of those list entries match with a specific file name?
Perhaps this would work for you:
string fileToSearch = "DATABASE.MDB";
bool found = files.Any(fileName => new FileInfo(fileName).Name.ToUpper() == fileToSearch.ToUpper());
Edit:
An alternative to constructing new FileInfo objects would be to use System.IO.Path:
bool found = files.Any(fileName => Path.GetFileName(fileName).ToUpper() == fileToSearch.ToUpper());
Edit 2:
On the other hand, if you want to search for a specific file name, and you want to use the result, you could do something like this:
var fileToSearch = "DATABASE.MDB";
var fileInfo =
(from f in files
let fi = new FileInfo(f)
where fi.Name.ToUpper() == fileToSearch.ToUpper()
select fi).FirstOrDefault();
if (fileInfo != null)
{
if (fileInfo.Exists)
{
Console.WriteLine($"{fileInfo.Name} ({fileInfo.Length} bytes).");
}
else
{
Console.WriteLine($"{fileInfo.Name} (does not exist).");
}
}
I used a LINQ query here for readability. You could use the extension methods (files.Select(f => new FileInfo(f)).Where(fi => fi.Name.ToUpper() == fileToSearch.ToUpper()).FirstOrDefault()) as well, but that's up to you.
if (Array.Exists(files, element => element.Contains(fileInfo.Name)))

C# get directories ordered by name starting from X

I need to get the directories within another directory but only those that are "after" X ordering them by dir name.
Example:
-Root
|--DirectoryA
|--DirectoryB
|--DirectoryC
|--DirectoryD
So basically something like this:
foreach(string path in Directory.GetDirectories("/root/"))
{
Console.WriteLine(path);
}
Output:
/root/DirectoryA
/root/DirectoryB
/root/DirectoryC
/root/DirectoryD
But I actually need to get only those after C (including it), I guess with Linq it shouldn't be too hard, but I really can't see how.
Maybe something like:
Directory.GetDirectories("/root/").OrderByDescending(dirName =>
Path.GetDirectoryName(dirName)) ??
You can use SkipWhile, assuming the order is alphabetical:
foreach(string path in Directory.GetDirectories("/root/")
.Select(dir => Path.GetFileName(dir))
.SkipWhile(dir => string.Compare(dir, "DirectoryC") < 0)
{
Console.WriteLine(path);
}
This way you will avoid redundant filtering will after encountering the first valid directory.
If you would want to take only the folders before DirectoryC you could use TakeWhile:
foreach(string path in Directory.GetDirectories("/root/")
.Select(dir => Path.GetFileName(dir))
.TakeWhile(dir => string.Compare(dir, "DirectoryC") < 0)
{
Console.WriteLine(path);
}
Note that string.Compare is culture dependent and you may use other overloads to customize its behavior.
Use the Where extension method
foreach(string path in Directory
.GetDirectories("/root/")
.Where(d => String.Compare(Path.GetFileName(d), "DirectoryC") > 0))
{
Console.WriteLine(path);
}
You can also include a ordering if you need it, but it will not influence the filtering with Where. If you do, append it after Where for efficiency.
or just in case that you are using an older version of .NET you can always write the logic yourself:
var directories = Directory.GetDirectories("C:\\").OrderByDescending(r => r).ToArray();
if (directories != null && directories.Length > 0)
{
for (int i = 0, Cindex=-1; i < directories.Length; i++)
{
if (Cindex > 0)
{
Console.WriteLine(directories[i]);
continue;
}
if (directories[i] == "DirectoryC")
{
Cindex = i;
}
}
}

How to get string value of a List<t> Item

I have some file paths stored in a List and need to attach them to an email. But how can I access the values (in my case: file paths as string values) of my List Items?
Here is the code:
List<string> filesToSend = new List<string>();
filesToSend = (List<string>)Session["filesListForFilesToSend"];
for (int i = 0; i < filesToSend.Count; i++)
{
//message.Attachments.Add(filesToSend[i].????????????????????);
}
Thanks in advance
filesToSend[i] will return the path string you want
Try This
foreach(string EachString in filesToSend)
{
message.Attachments.Add(EachString)
}
First, you do not need to instance a first list the after read the list in session, just:
List<string> filesToSend = (List<string>)Session["filesListForFilesToSend"];
When you access and List by index you will get the object of generic type. You can do it using a lot of ways, for sample:
using for loop:
for (int i = 0; i < filesToSend.Count; i++)
message.Attachments.Add(filesToSend[i]);
or foreach
foreach(string file in filesToSend)
message.Attachments.Add(file);
or while
int i = filesToSend.Lenght;
while(i--)
message.Attachments.Add(filesToSend[i]);
I would use foreach statement, but while will give you more performance (keep in mind you will loop in the reverse order).
The error was not how I was trying to get the string out of my List. The error was how I was trying to attach it to my message.
for (int i = 0; i < filesToSend.Count; i++)
{
string filePath = filesToSend[i];
Attachment attached = new Attachment(filePath);
attached.Name = filePath;
message.Attachments.Add(attached);
}
Thats the way it works for me. Thank you all

Archiving each string using by looping through an array

I am currently making a piece of software that will allow the user to enter up to 6 directories, each directory is saved as a string (within an array) the loop is then meant to check through the array and any that are not null i.e. actually have a directory assigned are meant to be zipped into their own archive. This is the code I have so far.
private void ZipIt()
{
int nxtFileNum = 0;
string Destination = #"C:\tmpZip" + nxtFileNum + ".zip";
// Check all fields, check if empty, if not save to Selection array
// Seems a inefficient - Possibly loop through Text box control type and collect?
if (String.IsNullOrEmpty(tboxSelect1.Text) == false) { BckupArray[0] = tboxSelect1.Text; };
if (String.IsNullOrEmpty(tboxSelect2.Text) == false) { BckupArray[1] = tboxSelect2.Text; };
if (String.IsNullOrEmpty(tboxSelect3.Text) == false) { BckupArray[2] = tboxSelect3.Text; };
if (String.IsNullOrEmpty(tboxSelect4.Text) == false) { BckupArray[3] = tboxSelect4.Text; };
if (String.IsNullOrEmpty(tboxSelect5.Text) == false) { BckupArray[4] = tboxSelect5.Text; };
if (String.IsNullOrEmpty(tboxSelect6.Text) == false) { BckupArray[5] = tboxSelect6.Text; };
// Create a new ZipFile entity and then loop through each array member, checking if
// it has an assigned value, if so compress it, if not, skip it.
using (ZipFile ZipIt = new ZipFile())
{
nxtFileNum++;
foreach (String q in BckupArray)
{
if (q != null)
{
ZipIt.AddDirectory(q);
ZipIt.Comment = "This archive was created at " + System.DateTime.Now.ToString("G");
ZipIt.Save(Destination);
}
}
}
}
What I am trying to get this to do is save the first user given location to tmpZip0.7z, the second to tmpZip1.7z and so on however at the moment all it is doing is adding each directory to tmpZip0.zip.
Also as a side note, how would I get it to name each archive after the directory selected to be archived?
I am currently using DotNetZip (Ionic.Zip) dll.
I hope I gave enough information guys.
You need to switch some stuff:
foreach (String q in BckupArray)
{
nxtFileNum++;
if (q != null)
{
using (ZipFile ZipIt = new ZipFile())
{
string Destination = #"C:\tmpZip" + nxtFileNum + ".zip";
ZipIt.AddDirectory(q);
ZipIt.Comment = "This archive was created at " +
System.DateTime.Now.ToString("G");
ZipIt.Save(Destination);
}
}
}
Reasons:
The string Destination is fixed after you created it. It doesn't change, just because you increment nxtFileNum.
You created only one ZipFile and you incremented nxtFileNum only once, because the those were outside of your foreach loop
Putting the part that creates the ZipFile into the if makes sure an instance is only created if it is really used.
Well, you can do this with:
var strings = Controls.OfType<TextBox>()
.Select(x => x.Text)
.Where(text => !string.IsNullOrEmpty(text))
.ToList();
using (ZipFile ZipIt = new ZipFile())
{
nxtFileNum++;
string comment = string.Format("This archive was created at {0:G}",
DateTime.Now);
foreach (string directory in strings)
{
ZipIt.AddDirectory(directory);
ZipIt.Comment = comment;
ZipIt.Save(Destination + "." + nxtFileNum);
}
}
That will obviously pull all the textboxes though. An alternative is to have a collection of type List<TextBox> or something similar instead of the six different variables.
Note that that will always create .1, .2, .3 etc even if the user didn't specify the first three names. Let me know if you want to be absolutely faithful to the positioning the user gave.
It's not clear to me that you should really be reusing the same ZipFile object, by the way. I'd expect this to be more appropriate:
string comment = string.Format("This archive was created at {0:G}",
DateTime.Now);
int fileIndex = 0;
foreach (string directory in strings)
{
fileIndex++;
using (ZipFile zipFile = new ZipFile())
{
zipFile.AddDirectory(directory);
zipFile.Comment = comment;
zipFile.Save(Destination + "." + fileIndex);
}
}
(Note how I've renamed the variables to be more conventional, by the way - variables typically start with a lower case letter.)

Compare adjacent list items

I'm writing a duplicate file detector. To determine if two files are duplicates I calculate a CRC32 checksum. Since this can be an expensive operation, I only want to calculate checksums for files that have another file with matching size. I have sorted my list of files by size, and am looping through to compare each element to the ones above and below it. Unfortunately, there is an issue at the beginning and end since there will be no previous or next file, respectively. I can fix this using if statements, but it feels clunky. Here is my code:
public void GetCRCs(List<DupInfo> dupInfos)
{
var crc = new Crc32();
for (int i = 0; i < dupInfos.Count(); i++)
{
if (dupInfos[i].Size == dupInfos[i - 1].Size || dupInfos[i].Size == dupInfos[i + 1].Size)
{
dupInfos[i].CheckSum = crc.ComputeChecksum(File.ReadAllBytes(dupInfos[i].FullName));
}
}
}
My question is:
How can I compare each entry to its neighbors without the out of bounds error?
Should I be using a loop for this, or is there a better LINQ or other function?
Note: I did not include the rest of my code to avoid clutter. If you want to see it, I can include it.
Compute the Crcs first:
// It is assumed that DupInfo.CheckSum is nullable
public void GetCRCs(List<DupInfo> dupInfos)
{
dupInfos[0].CheckSum = null ;
for (int i = 1; i < dupInfos.Count(); i++)
{
dupInfos[i].CheckSum = null ;
if (dupInfos[i].Size == dupInfos[i - 1].Size)
{
if (dupInfos[i-1].Checksum==null) dupInfos[i-1].CheckSum = crc.ComputeChecksum(File.ReadAllBytes(dupInfos[i-1].FullName));
dupInfos[i].CheckSum = crc.ComputeChecksum(File.ReadAllBytes(dupInfos[i].FullName));
}
}
}
After having sorted your files by size and crc, identify duplicates:
public void GetDuplicates(List<DupInfo> dupInfos)
{
for (int i = dupInfos.Count();i>0 i++)
{ // loop is inverted to allow list items deletion
if (dupInfos[i].Size == dupInfos[i - 1].Size &&
dupInfos[i].CheckSum != null &&
dupInfos[i].CheckSum == dupInfos[i - 1].Checksum)
{ // i is duplicated with i-1
... // your code here
... // eventually, dupInfos.RemoveAt(i) ;
}
}
}
I have sorted my list of files by size, and am looping through to
compare each element to the ones above and below it.
The next logical step is to actually group your files by size. Comparing consecutive files will not always be sufficient if you have more than two files of the same size. Instead, you will need to compare every file to every other same-sized file.
I suggest taking this approach
Use LINQ's .GroupBy to create a collection of files sizes. Then .Where to only keep the groups with more than one file.
Within those groups, calculate the CRC32 checksum and add it to a collection of known checksums. Compare with previously calculated checksums. If you need to know which files specifically are duplicates you could use a dictionary keyed by this checksum (you can achieve this with another GroupBy. Otherwise a simple list will suffice to detect any duplicates.
The code might look something like this:
var filesSetsWithPossibleDupes = files.GroupBy(f => f.Length)
.Where(group => group.Count() > 1);
foreach (var grp in filesSetsWithPossibleDupes)
{
var checksums = new List<CRC32CheckSum>(); //or whatever type
foreach (var file in grp)
{
var currentCheckSum = crc.ComputeChecksum(file);
if (checksums.Contains(currentCheckSum))
{
//Found a duplicate
}
else
{
checksums.Add(currentCheckSum);
}
}
}
Or if you need the specific objects that could be duplicates, the inner foreach loop might look like
var filesSetsWithPossibleDupes = files.GroupBy(f => f.FileSize)
.Where(grp => grp.Count() > 1);
var masterDuplicateDict = new Dictionary<DupStats, IEnumerable<DupInfo>>();
//A dictionary keyed by the basic duplicate stats
//, and whose value is a collection of the possible duplicates
foreach (var grp in filesSetsWithPossibleDupes)
{
var likelyDuplicates = grp.GroupBy(dup => dup.Checksum)
.Where(g => g.Count() > 1);
//Same GroupBy logic, but applied to the checksum (instead of file size)
foreach(var dupGrp in likelyDuplicates)
{
//Create the key for the dictionary (your code is likely different)
var sample = dupGrp.First();
var key = new DupStats() {FileSize = sample.FileSize, Checksum = sample.Checksum};
masterDuplicateDict.Add(key, dupGrp);
}
}
A demo of this idea.
I think the for loop should be : for (int i = 1; i < dupInfos.Count()-1; i++)
var grps= dupInfos.GroupBy(d=>d.Size);
grps.Where(g=>g.Count>1).ToList().ForEach(g=>
{
...
});
Can you do a union between your two lists? If you have a list of filenames and do a union it should result in only a list of the overlapping files. I can write out an example if you want but this link should give you the general idea.
https://stackoverflow.com/a/13505715/1856992
Edit: Sorry for some reason I thought you were comparing file name not size.
So here is an actual answer for you.
using System;
using System.Collections.Generic;
using System.Linq;
public class ObjectWithSize
{
public int Size {get; set;}
public ObjectWithSize(int size)
{
Size = size;
}
}
public class Program
{
public static void Main()
{
Console.WriteLine("start");
var list = new List<ObjectWithSize>();
list.Add(new ObjectWithSize(12));
list.Add(new ObjectWithSize(13));
list.Add(new ObjectWithSize(14));
list.Add(new ObjectWithSize(14));
list.Add(new ObjectWithSize(18));
list.Add(new ObjectWithSize(15));
list.Add(new ObjectWithSize(15));
var duplicates = list.GroupBy(x=>x.Size)
.Where(g=>g.Count()>1);
foreach (var dup in duplicates)
foreach (var objWithSize in dup)
Console.WriteLine(objWithSize.Size);
}
}
This will print out
14
14
15
15
Here is a netFiddle for that.
https://dotnetfiddle.net/0ub6Bs
Final note. I actually think your answer looks better and will run faster. This was just an implementation in Linq.

Categories

Resources