我在使用文件锁定的多进程环境时成功读取文件 在多线程(单进程)的情况下,我使用一个用文件名填充它的队列,分别打开一个线程,从中读取然后等待整个读取结束,之后我用它来重命名它们。通过这种方式,我习惯于以多线程(批量)读取文件。
现在,我想使用多进程和多线程读取目录中的文件。我尝试合并我的两种方法,但这并不好。 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;
}
}
我想知道,如果我可以采用其他方法。
答案 0 :(得分:4)
如果要创建对文件的独占访问权限,则不能使用文件锁定,因为在大多数操作系统上,文件锁定是建议性的,不是强制性的。
我建议为所有进程创建一个公共锁定目录;在此锁定目录中,您将在打开文件之前为每个要锁定的文件创建目录。
最大的好处是,与文件创建不同,目录创建是原子的;因此,您可以使用Files.createDirectory()
(或文件的.mkdir()
,如果您仍然使用Java6,但不要忘记检查返回代码)以获取您读取的文件的锁定。如果失败,您就知道其他人正在使用该文件。
当然,当你完成一个文件时,不要忘记删除与该文件匹配的锁定目录...(在finally
块中)
(注意:使用Java 7,您可以使用Files.newBufferedReader()
;甚至可以使用Files.readAllLines()
)
答案 1 :(得分:0)
如果您需要使用多个线程处理大量文件,您应该首先将特定文件分发到每个线程,然后再启动。
例如,如果您只想处理名称以email
开头且后跟一些数字的文件,则可以创建10个线程。第一个线程将查找名称以email0
开头的文件,第二个线程可以处理email1
等。
这当然只有在数字均匀分布时才有效。
另一种方法可能是让主线程运行并收集所有要处理的文件名。然后,它可以跨越可用线程的数量划分文件,并将每个线程传递给这些文件名的数组。
可能有其他方法来划分与您的情况相关的系统负载。