如何在多进程,多线程环境中读取文件

时间:2013-06-17 09:01:03

标签: java multithreading file-io multiprocessing

我在使用文件锁定的多进程环境时成功读取文件 在多线程(单进程)的情况下,我使用一个用文件名填充它的队列,分别打开一个线程,从中读取然后等待整个读取结束,之后我用它来重命名它们。通过这种方式,我习惯于以多线程(批量)读取文件。

现在,我想使用多进程和多线程读取目录中的文件。我尝试合并我的两种方法,但这并不好。 log显示很多文件显示FileNotFound异常(因为它们的名称被更改),有些从未读过(因为线程死了),有时锁没有被释放。

 ///////////////////////////////////////////////////////////////////////
     //file filter inner class
     class myfilter implements FileFilter{

            @Override
            public boolean accept(File pathname) {
                // TODO Auto-generated method stub
                Pattern pat = Pattern.compile("email[0-9]+$");
                Matcher mat = pat.matcher(pathname.toString());
                if(mat.find()) {
                    return true;
                }
                return false;
            }

        }
     /////////////////////////////////////////////////////////////////////////


    myfilter filter = new myfilter();
    File alreadyread[] = new File[5];
    Thread t[] = new Thread[5];
    fileread filer[] = new fileread[5];
    File file[] = directory.listFiles(filter);
    FileChannel filechannel[] = new FileChannel[5];
    FileLock lock[] = new FileLock[5];
    tuple_json = new ArrayList();
    //System.out.println("ayush");
    while(true) {
        //declare a queue
        ConcurrentLinkedQueue filequeue = new ConcurrentLinkedQueue();

        //addfilenames to queue and their renamed file names
        try{
        if(file.length!=0) {
            //System.out.println(file.length);
            for(int i=0;i<5 && i<file.length;i++) {

                System.out.println("acquiring lock on file " + file[i].toString());
                try{
                filechannel[i] = new RandomAccessFile(file[i], "rw").getChannel();
                lock[i] = filechannel[i].tryLock();
                }
                catch(Exception e) {
                    file[i] = null;
                    lock[i] = null;
                    System.out.println("cannot acquire lock");
                }
                if(lock[i]!=null){
                    System.out.println("lock acquired on file " + file[i].toString());
                   filequeue.add(file[i]);
                   alreadyread[i] = new File(file[i].toString() + "read");
                   System.out.println(file[i].toString() + "-----" + times);
                }
                else{

                   System.out.println("else condition of acquiring lock");
                    file[i] = null;
                }
                System.out.println("-----------------------------------");
            }

        //starting the thread to read the files
        for(int i=0;i<5 && i<file.length && lock[i]!=null && file[i]!=null;i++){
            filer[i] = new fileread(filequeue.toArray()[i].toString());
            t[i] = new Thread(filer[i]);
            System.out.println("starting a thread to read file" + file[i].toString());
            t[i].start();
        }

        //read the text
        for(int i=0;i<5 && i<file.length && lock[i]!=null && file[i]!=null;i++) {
            try {
                System.out.println("waiting to read " + file[i].toString() + " to be read completely");
                t[i].join();
                System.out.println(file[i] + " was read completetly");
                //System.out.println(filer[i].getText());

            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
        //file has been read Now rename the file
        for(int i=0;i<5 && i<file.length && lock[i]!=null && file[i]!=null;i++){
            if(lock[i]!=null){
                System.out.println("renaming file " + file[i].toString());
                file[i].renameTo(alreadyread[i]);
                System.out.println("releasing lock on file  " + file[i].toString());
                lock[i].release();
        }
        }

//rest of the processing
/////////////////////////////////////////////////////////////////////////////////////////////////////

Fileread class

class fileread implements Runnable{
//String loc = "/home/ayusun/workspace/Eclipse/fileread/bin";
String fileloc;
BufferedReader br;
String text = "";
public fileread(String filename) {
    this.fileloc = filename;
}
@Override
public void run() {
    try {
        br = new BufferedReader(new FileReader(fileloc));
        System.out.println("started reading file" + fileloc);
        String currline;
        while((( currline = br.readLine())!=null)){
            if(text == "")
                text += currline;
            else
                text += "\n" + currline;
        }

        System.out.println("Read"  + fileloc  + " completely");
        br.close();

    } catch ( IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

public String getText() {
    return text;
}
}

我想知道,如果我可以采用其他方法。

2 个答案:

答案 0 :(得分:4)

如果要创建对文件的独占访问权限,则不能使用文件锁定,因为在大多数操作系统上,文件锁定是建议性的,不是强制性的。

我建议为所有进程创建一个公共锁定目录;在此锁定目录中,您将在打开文件之前为每个要锁定的文件创建目录

最大的好处是,与文件创建不同,目录创建是原子的;因此,您可以使用Files.createDirectory()(或文件的.mkdir(),如果您仍然使用Java6,但不要忘记检查返回代码)以获取您读取的文件的锁定。如果失败,您就知道其他人正在使用该文件。

当然,当你完成一个文件时,不要忘记删除与该文件匹配的锁定目录...(在finally块中)

(注意:使用Java 7,您可以使用Files.newBufferedReader();甚至可以使用Files.readAllLines()

答案 1 :(得分:0)

如果您需要使用多个线程处理大量文件,您应该首先将特定文件分发到每个线程,然后再启动。

例如,如果您只想处理名称以email开头且后跟一些数字的文件,则可以创建10个线程。第一个线程将查找名称以email0开头的文件,第二个线程可以处理email1等。

这当然只有在数字均匀分布时才有效。

另一种方法可能是让主线程运行并收集所有要处理的文件名。然后,它可以跨越可用线程的数量划分文件,并将每个线程传递给这些文件名的数组。

可能有其他方法来划分与您的情况相关的系统负载。