none
.net4 用并行计算的方式,把目录下所有jpg文件放到datatable里面 RRS feed

  • 问题

  • .net4 用并行计算的方式,把指定目录及其所有子目录下的所有jpg文件放到一个datatable里面,datatable存放有不重复的序号,文件名(无扩展名),文件的扩展名三个字段!不用并行的方式就会写,但是用并行方式好像无从下手的样子,请高手们指点一下,放一些核心的代码给我参考参考。多谢!
    2012年7月17日 15:22

答案

  • 参考:http://msdn.microsoft.com/zh-cn/library/dd460720.aspx

    以下我根据你题目给出的例子

    public class Program
        {
            static void Main(string[] args)
            {
                DataTable dt = new DataTable();
                dt.Columns.Add("Id"typeof(int));
                dt.Columns.Add("FileName"typeof(string));
                dt.Columns.Add("ExtensionName"typeof(string));
                dt.Columns[0].AutoIncrement = true;
                dt.Columns[0].AutoIncrementSeed = 1;
                dt.Columns[0].AutoIncrementStep = 1;
                Parallel.ForEach<string>(Directory.GetFiles("C:\\安装","*.jpg",SearchOption.AllDirectories), (s) =>
                {
                    DataRow row = dt.NewRow();
                    row["FileName"] = Path.GetFileName(s);
                    row["ExtensionName"] = Path.GetExtension(s);
                    dt.Rows.Add(row);
                });
     
                foreach (DataRow item in dt.Rows)
                {
                    Console.WriteLine(item["Id"].ToString()+"<==>"+item["FileName"]+"<==>"+item["ExtensionName"].ToString());
                }
            }
        }

    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    • 已标记为答案 rackly 2012年7月18日 8:07
    2012年7月18日 2:08
    版主
  • 以下用for:

    public class Program
        {
            /// <summary>
            /// Each time process with 3 files
            /// </summary>
            public const int BLOCKFILEPROCESS = 3;
     
            static void Main(string[] args)
            {
                DataTable dt = new DataTable();
                dt.Columns.Add("Id"typeof(int));
                dt.Columns.Add("FileName"typeof(string));
                dt.Columns.Add("ExtensionName"typeof(string));
                dt.Columns[0].AutoIncrement = true;
                dt.Columns[0].AutoIncrementSeed = 1;
                dt.Columns[0].AutoIncrementStep = 1;
     
                string[] files = Directory.GetFiles("c:\\安装""*.jpg"SearchOption.TopDirectoryOnly);
                int totalFiles = files.Length;
                int finalThreadNum = totalFiles / BLOCKFILEPROCESS == 0 ? (totalFiles / BLOCKFILEPROCESS) : (totalFiles / BLOCKFILEPROCESS + 1);
     
                Parallel.For<string[]>(0, finalThreadNum, () => files, (i, state, processCollection) => 
                {
                   return processCollection.Skip(i*BLOCKFILEPROCESS).Take(BLOCKFILEPROCESS).ToArray();
                }, 
                (result) => 
                {
                    foreach (var item in result)
                    {
                        DataRow row = dt.NewRow();
                        row["FileName"] = Path.GetFileName(item);
                        row["ExtensionName"] = Path.GetExtension(item);
                        dt.Rows.Add(row);
                    }
                });
     
                foreach (DataRow item in dt.Rows)
                {
                    Console.WriteLine(item["Id"].ToString() + "<==>" + item["FileName"] + "<==>" + item["ExtensionName"].ToString());
                }
            }
        }

    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    • 已标记为答案 rackly 2012年7月18日 8:07
    2012年7月18日 2:45
    版主
  • 我改写datasethelper的Distinct成功了!

    共享给大家:       

    public DataTable Distinct(string tableName, DataTable sourceTable, string[] fieldNames)
    {
        DataTable dt = sourceTable.Clone();//结果存放的地方
        DataTable dttemp = sourceTable.Clone();//原始字段结构存放
        dt.TableName = tableName;//表明
        DataColumnCollection dccs = dttemp.Columns;//比较用的字段集
        string fields = "";//select排序参数结果存放处
        dccs.Clear();//清除引用dttemp的字段集
        for (int i = 0; i < fieldNames.Length; i++)
        {
            fields += fieldNames[i] + " asc,";//字段集都是按ASC排序
            dccs.Add(new DataColumn(fieldNames[i]));//加入自己定义的字段
        }
        fields = fields.Remove(fields.Length - 1, 1);//删除后面的逗号
        DataRow lastRow = null;
        foreach (DataRow dr in sourceTable.Select("", fields))
        {
            if (lastRow == null || !(RowEqual(lastRow, dr, dccs)))
            {
                lastRow = dr;
                dt.ImportRow(dr);
            }
        }
        //这个我不知道如何用!所以不用,减少资源付出
        //if (ds != null && !ds.Tables.Contains(tableName))
        //{
        //    ds.Tables.Add(dt);
        //}
        return dt;
    }

    2012年7月26日 8:57

全部回复

  • 参考:http://msdn.microsoft.com/zh-cn/library/dd460720.aspx

    以下我根据你题目给出的例子

    public class Program
        {
            static void Main(string[] args)
            {
                DataTable dt = new DataTable();
                dt.Columns.Add("Id"typeof(int));
                dt.Columns.Add("FileName"typeof(string));
                dt.Columns.Add("ExtensionName"typeof(string));
                dt.Columns[0].AutoIncrement = true;
                dt.Columns[0].AutoIncrementSeed = 1;
                dt.Columns[0].AutoIncrementStep = 1;
                Parallel.ForEach<string>(Directory.GetFiles("C:\\安装","*.jpg",SearchOption.AllDirectories), (s) =>
                {
                    DataRow row = dt.NewRow();
                    row["FileName"] = Path.GetFileName(s);
                    row["ExtensionName"] = Path.GetExtension(s);
                    dt.Rows.Add(row);
                });
     
                foreach (DataRow item in dt.Rows)
                {
                    Console.WriteLine(item["Id"].ToString()+"<==>"+item["FileName"]+"<==>"+item["ExtensionName"].ToString());
                }
            }
        }

    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    • 已标记为答案 rackly 2012年7月18日 8:07
    2012年7月18日 2:08
    版主
  • 以下用for:

    public class Program
        {
            /// <summary>
            /// Each time process with 3 files
            /// </summary>
            public const int BLOCKFILEPROCESS = 3;
     
            static void Main(string[] args)
            {
                DataTable dt = new DataTable();
                dt.Columns.Add("Id"typeof(int));
                dt.Columns.Add("FileName"typeof(string));
                dt.Columns.Add("ExtensionName"typeof(string));
                dt.Columns[0].AutoIncrement = true;
                dt.Columns[0].AutoIncrementSeed = 1;
                dt.Columns[0].AutoIncrementStep = 1;
     
                string[] files = Directory.GetFiles("c:\\安装""*.jpg"SearchOption.TopDirectoryOnly);
                int totalFiles = files.Length;
                int finalThreadNum = totalFiles / BLOCKFILEPROCESS == 0 ? (totalFiles / BLOCKFILEPROCESS) : (totalFiles / BLOCKFILEPROCESS + 1);
     
                Parallel.For<string[]>(0, finalThreadNum, () => files, (i, state, processCollection) => 
                {
                   return processCollection.Skip(i*BLOCKFILEPROCESS).Take(BLOCKFILEPROCESS).ToArray();
                }, 
                (result) => 
                {
                    foreach (var item in result)
                    {
                        DataRow row = dt.NewRow();
                        row["FileName"] = Path.GetFileName(item);
                        row["ExtensionName"] = Path.GetExtension(item);
                        dt.Rows.Add(row);
                    }
                });
     
                foreach (DataRow item in dt.Rows)
                {
                    Console.WriteLine(item["Id"].ToString() + "<==>" + item["FileName"] + "<==>" + item["ExtensionName"].ToString());
                }
            }
        }

    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    • 已标记为答案 rackly 2012年7月18日 8:07
    2012年7月18日 2:45
    版主
  • 感谢您的回答!非常符合我的要求!而且并行计算还比较难转换过来啊!

    原来我这么做的:

    把所有文件(三个属性)都放进datatable里面,过滤jpg、png、bmp等图片!

    然后再放进另外一个表输出!

    然后改并行的时候,遇到foreach的时候用datarow出错的问题!

    现在好了!用您的方法可以解决了!

    2012年7月18日 8:13
  • 不用谢!如果你文件数量不是很多并行不一定好。你的机器是“真双核”吗?


    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年7月18日 9:01
    版主
  • 我的机子是E5400!应该算双核啦!你说的真双核是服务器那种双CPU的那种!?

    从你的代码改写成我的代码后,代码出现了不稳定的满负荷状态!本来几百毫秒的事情,一下子等了五分钟都没有结束!

    所以觉得是不是我改坏了代码,因为我的字段多加了文件大小的东西,所以加了一下代码:

                Parallel.ForEach<string>(Directory.GetFiles(photofoler, "*.*", SearchOption.AllDirectories), (s) =>
                {
                    FileInfo fi = new FileInfo(s);
                    DataRow row = dt.NewRow();
                    row["filename"] = formatfilename(fi.Name);
                    row["filesize"] = fi.Length;
                    row["filepath"] = s;
                    dt.Rows.Add(row);
                });

    给给看法,我现在还是用回串行的方法!因为只处理5000左右个文件,效率和并行差不多,并行快几十毫秒的样子!

    接着可能要问另外的问题了!

    datatable如何过滤组合重复的值?

    事情经过:有人发照片给我,我就放在要处理文件夹A里,然后所有照片整理入库(放在整理文件夹B),然后我用拷贝+入库的方法做了,

    但是有些情况,就是我要求把这个人名做成图片文件名发过来文件夹A,有时别人打错字了,改名重新发图片过来,

    然后我重新处理入库的时候就会发觉:1.不同名字,但是文件大小相同。2.文件大小不同,而名字一样的情况!

    所以苦于解决这个问题上!现在用datesethelper的Distinct可以做到单个字段的过滤,但是多个字段组合就不行了,正在研究改写!

    请给点意见!


    • 已编辑 rackly 2012年7月21日 10:18
    2012年7月21日 10:14
  • 第一个问题:改动增加一个文件大小应该不会有所损害,请检查你里边是不是有特别大的尺寸文件,导致内部计算的时候停顿了?

    第二个问题:多个字段组合,使用DataView.ToTable(字段,是否使用Distinct:http://msdn.microsoft.com/zh-cn/library/wec2b2e6(v=vs.80)


    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年7月22日 1:31
    版主
  • 第一个:里面最大的文件有10MB的大小,有超界的数字,后来我都除以1024,小一个数量级,基本就没有超界了!

    但是还是有死循环的情况!不知道是不是跟我用stopwatch有关?还是前后用测试有关!前后测试指的是写了两个方法,一个并行一个串行,并行放前面测试,没有问题,在串行后面测的话,十次有一两次,会卡在哪里!

    第二个:DataView.ToTable已经用过了!两个字段使用就是要得出这样的结果!但是情况是:

    ID filename filesize filepath
    103 李明浩 2157420 D:\开发资料\门卡数量上报区\2011-4\李明浩.JPG
    103 李明浩 2157420 D:\开发资料\门卡数量上报区\2010-Ver1\技术班\李明浩2.JPG
    103 李明浩 2157420 D:\开发资料\门卡数量上报区\2011-9\技术班\李明浩.JPG
    103 李明浩 3002636 D:\开发资料\门卡数量上报区\2010-Ver1\三号班\李明浩.JPG
    103 李明浩 3002636 D:\开发资料\门卡数量上报区\2011-9\三号班\李明浩.JPG

    有些人是同名同姓的路径也有不同,我只想过滤得到:

    103 李明浩 2157420 D:\开发资料\门卡数量上报区\2011-4\李明浩.JPG
    103 李明浩 3002636 D:\开发资料\门卡数量上报区\2010-Ver1\三号班\李明浩.JPG

    这个人的两个数据,再人工看哪个才是那个人的!


    2012年7月22日 14:03
  • 我改写datasethelper的Distinct成功了!

    共享给大家:       

    public DataTable Distinct(string tableName, DataTable sourceTable, string[] fieldNames)
    {
        DataTable dt = sourceTable.Clone();//结果存放的地方
        DataTable dttemp = sourceTable.Clone();//原始字段结构存放
        dt.TableName = tableName;//表明
        DataColumnCollection dccs = dttemp.Columns;//比较用的字段集
        string fields = "";//select排序参数结果存放处
        dccs.Clear();//清除引用dttemp的字段集
        for (int i = 0; i < fieldNames.Length; i++)
        {
            fields += fieldNames[i] + " asc,";//字段集都是按ASC排序
            dccs.Add(new DataColumn(fieldNames[i]));//加入自己定义的字段
        }
        fields = fields.Remove(fields.Length - 1, 1);//删除后面的逗号
        DataRow lastRow = null;
        foreach (DataRow dr in sourceTable.Select("", fields))
        {
            if (lastRow == null || !(RowEqual(lastRow, dr, dccs)))
            {
                lastRow = dr;
                dt.ImportRow(dr);
            }
        }
        //这个我不知道如何用!所以不用,减少资源付出
        //if (ds != null && !ds.Tables.Contains(tableName))
        //{
        //    ds.Tables.Add(dt);
        //}
        return dt;
    }

    2012年7月26日 8:57
  • dt.Rows.Add(row); 非线程安全,并行的话有问题。
    2012年7月26日 9:05