使用单独的线程在java中读取和写入文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29339933/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 07:47:49  来源:igfitidea点击:

read and write files in java using separate threads

javamultithreading

提问by Salman Farooq

I have created two threads and modified the run function so that one thread reads one line and the other writes the same line to the new file. This happens till the whole file is copied. The problem i am getting is that even though i have used variables to control that the threads execute one by one but still the threads are executing unevenly i.e one thread executes multiple times and then the control transfers. Any solutions i have attached the code. I am new to java as it is only for class assignment so the code might not be the most optimized.

我创建了两个线程并修改了 run 函数,以便一个线程读取一行,另一个线程将同一行写入新文件。这种情况会发生,直到整个文件被复制。我遇到的问题是,即使我使用变量来控制线程一个一个执行,但线程仍然执行不均匀,即一个线程执行多次,然后控制转移。我附上了代码的任何解决方案。我是 Java 新手,因为它仅用于类分配,因此代码可能不是最优化的。

  public class thread1 extends Thread {
    //To create producer and consumer as threads
        //Shared variable
        public static int x = 0;//checks if all lines are read                                      
        public static String line; /holds lines from file
        public static int j = 0;//variable to switch between threads based upon its value

        public thread1(String threadName) {     //Constuctor
            super(threadName);      //Call to constructor of Thread class
        }

        public void run() {

            while (x != -1)
            {
                if (Thread.currentThread().getName().contains("Reader")) {
                    if (x != -1&&j==0)
                    {
                   j=1;
                    String fileName = "d:/salfar.txt";


                    try {
                        // FileReader reads text files in the default encoding.
                        FileReader fileReader =
                                new FileReader(fileName);

                        // Always wrap FileReader in BufferedReader.
                        BufferedReader bufferedReader =
                                new BufferedReader(fileReader);

                        for (int check = 0; check <= x; check++) {

                            line = bufferedReader.readLine();
                        }
                        if (line == null) {
                            x = -1;
                        } else {
                            System.out.println(line);

                            x++;
                        }


                        // Always close files.
                        bufferedReader.close();
                    } catch (FileNotFoundException ex) {
                        System.out.println(
                                "Unable to open file '"
                                + fileName + "'");
                    } catch (IOException ex) {
                        System.out.println(
                                "Error reading file '"
                                + fileName + "'");
                        // Or we could just do this: 
                        // ex.printStackTrace();

                    }
                    }

                    yield();
                } 
                else if (Thread.currentThread().getName().contains("writer")) {
    if (x != -1 && line != null&&j==1)
    {
                    j=0;

                    String fileName = "d:/salfar1.txt";

                    try {
                        // Assume default encoding.
                        FileWriter fileWriter =
                                new FileWriter(fileName, true);

                        // Always wrap FileWriter in BufferedWriter.
                        BufferedWriter bufferedWriter =
                                new BufferedWriter(fileWriter);

                        // Note that write() does not automatically
                        // append a newline character.
                        bufferedWriter.write(line);
                        bufferedWriter.newLine();
                        System.out.println("y");
                        // Always close files.
                        bufferedWriter.close();
                    } catch (IOException ex) {
                        System.out.println(
                                "Error writing to file '"
                                + fileName + "'");
                        // Or we could just do this:
                        // ex.printStackTrace();
                    }
    }     
                    Thread.yield();
                }
                else{}
            }
        }

        public static void main(String[] args) {

            thread1 p = new thread1("Reader");
            thread1 c = new thread1("writer");

            p.start();
            c.start();


        }
    }


    Thanks

采纳答案by Touchstone

You cannot control the order of thread execution. However, to perform read and write operation via separate threads, you should use BlockingQueue which has the following properties:

您无法控制线程执行的顺序。但是,要通过单独的线程执行读写操作,您应该使用具有以下属性的 BlockingQueue:

A Queue that additionally supports operations that wait for the queue to become non-empty when retrieving an element, and wait for space to become available in the queue when storing an element.

一个 Queue 额外支持在检索元素时等待队列变为非空的操作,并在存储元素时等待队列中的空间变为可用。

ReaderThread will read from the input file.

ReaderThread 将从输入文件中读取。

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;

public class ReaderThread implements Runnable{

  protected BlockingQueue<String> blockingQueue = null;

  public ReaderThread(BlockingQueue<String> blockingQueue){
    this.blockingQueue = blockingQueue;     
  }

  @Override
  public void run() {
    BufferedReader br = null;
     try {
            br = new BufferedReader(new FileReader(new File("./inputFile.txt")));
            String buffer =null;
            while((buffer=br.readLine())!=null){
                blockingQueue.put(buffer);
            }
            blockingQueue.put("EOF");  //When end of file has been reached

        } catch (FileNotFoundException e) {

            e.printStackTrace();
        } catch (IOException e) {

            e.printStackTrace();
        } catch(InterruptedException e){

        }finally{
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


  }



}

WriterThread will write to output file.

WriterThread 将写入输出文件。

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.concurrent.BlockingQueue;

public class WriterThread implements Runnable{

  protected BlockingQueue<String> blockingQueue = null;

  public WriterThread(BlockingQueue<String> blockingQueue){
    this.blockingQueue = blockingQueue;     
  }

  @Override
  public void run() {
    PrintWriter writer = null;

    try {
        writer = new PrintWriter(new File("outputFile.txt"));

        while(true){
            String buffer = blockingQueue.take();
            //Check whether end of file has been reached
            if(buffer.equals("EOF")){ 
                break;
            }
            writer.println(buffer);
        }               


    } catch (FileNotFoundException e) {

        e.printStackTrace();
    } catch(InterruptedException e){

    }finally{
        writer.close();
    } 

  }

}

From Launcher class start your multithreaded read and write.

从 Launcher 类开始您的多线程读写。

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class Launcher {

  public static void main(String[] args) {

    BlockingQueue<String> queue = new ArrayBlockingQueue<String>(1024);

    ReaderThread reader = new ReaderThread(queue);
    WriterThread writer = new WriterThread(queue);

    new Thread(reader).start();
    new Thread(writer).start();

  }

 }

回答by mkk700

Here is my solutions. My idea is to use the actually file name that our threads will be reading and writing to. There is only one issue that we need to make sure of, that no two threads are trying to operate on the same file. The solution to this is to simply have a synchronized code block in your run method.

这是我的解决方案。我的想法是使用我们的线程将读取和写入的实际文件名。我们只需要确定一个问题,即没有两个线程试图对同一个文件进行操作。解决这个问题的方法是在你的 run 方法中简单地有一个同步的代码块。

We must recall that Strings are not mutable in Java. Consider the following:

我们必须记住,字符串在 Java 中是不可变的。考虑以下:

String s1 = "test.txt";
String s2 = "test.txt";

Now, we must ask our selves how does the jvm reuse the immutable "test.txt". In this case both s1 & s2 String objects point to the same "test.txt".

现在,我们必须问问自己,jvm 如何重用不可变的“test.txt”。在这种情况下,s1 和 s2 字符串对象都指向相同的“test.txt”。

Understanding this concept will also do the trick for us:

理解这个概念也会为我们提供帮助:

public class Client {

public static void main( String args [] ) {

    String filename = "test.txt";
    String filename2 = "test.txt";

    Reader reader = new Reader( filename ) ; 
    Writer writer = new Writer( filename2 ) ;

    while(true) {
        reader.run();
        writer.run();
    }

  }
} 

public class Writer implements Runnable {

public String filename; 

public Writer( String filename ) {
    this.filename = filename; 
}

@Override
public void run() { 

    synchronized( this.filename ) {
        System.out.println( "writing to a file:" + this.filename );  
    }  

 }
}


public class Reader implements Runnable {

public String filename; 

public Reader( String filename ) {
    this.filename = filename; 
}

@Override
public void run() { 

    synchronized( this.filename ) {
        System.out.println( "reading a file:" + this.filename );
    } 

}
}