在java中通过asynchronousFileChannel写入时丢失数据

Posted

技术标签:

【中文标题】在java中通过asynchronousFileChannel写入时丢失数据【英文标题】:losing data while writing through asynchronousFileChannel in java 【发布时间】:2013-09-20 04:59:36 【问题描述】:

我正在尝试使用 asynchronousFileChannel 将日期写入文本文件。我使用 AsynchronousFileChannel 制作了程序的 3 个 jar 文件,并通过命令提示符同时编译了所有 3 个 jar,以读取 3 个不同的文本文件并输出到一个公共临时文件

我的测试文件中有 2000 条记录(3) 需要读取,但是普通临时文件中的输出缺少一些记录,输出应该有 6000 条记录但它只显示 5366 或 5666 或有时少于那个。

我无法弄清楚为什么某些数据会丢失,因为它是 asynchronousFileChannel 的功能。 这是使用异步文件通道的java程序的代码。

        class Writer()
            public void writeOut(ReadableData fileData)
           throws InterruptedException 
           Path file = null;
          AsynchronousFileChannel asynchFileChannel = null;
          String filePath = tempFileName;
    try 
               file = Paths.get(filePath);
                asynchFileChannel = AsynchronousFileChannel.open(file,
                StandardOpenOption.WRITE, StandardOpenOption.CREATE);

            CompletionHandler<Integer, Object> handler = new CompletionHandler<Integer, Object>() 
             @Override
            public void completed(Integer result, Object attachment) 
                 if (result == Integer.MAX_VALUE) 
                log.debug("Attachment: " + attachment + " " + result
                        + " bytes written");
                log.debug("CompletionHandler Thread ID: "
                        + Thread.currentThread().getId());
                
                result++;
               
               @Override
            public void failed(Throwable e, Object attachment) 
                try 
                    throw e;
                 catch (Throwable e1) 
                    e1.printStackTrace();
                
                log.debug("File Write Failed Exception:");
                e.printStackTrace();
            
        ;

        String printData = fileData.getId() + "|"
                + fileData.getName() + "|" + fileData.getEmpId()
                + "|" + fileData.getServieId() + "|" + "\n";

        asynchFileChannel.write(ByteBuffer.wrap(printData.getBytes()),
                asynchFileChannel.size(), "file write", handler);

        log.debug(printData);
                   
      
    catch (IOException e) 
        e.printStackTrace();
        log.error(e.getMessage());
     finally 

     

这是我从 3 个文件中读取数据的课程:

 public class FileReader1 
static Logger log = Logger.getLogger(FileHandlerNorthBoundMain.class
        .getName());        
        Writer wrO=new Writer();

public static void main(String[] args) throws IOException,
        IllegalFileFormatException, InterruptedException 
        String filePath = "C:\\Users\\Public\\testdata1.csv"; //"C:\\Users\\Public\\testdata2.csv";  "C:\\Users\\Public\\testdata3.csv";
        File file = new File(filePath);
        log.info("Fetching data.... from:  " + filePath);
    ArrayList<ReadableData> list = new ArrayList<ReadableData>();
    FileInputStream fs = null;
    BufferedReader reader = null;
    String Name;
    int Id, EmpId, ServiceId;
    ReadableData readableData = null;
    int count = 0;
    fs = new FileInputStream(file);
    reader = new BufferedReader(new InputStreamReader(fs));
    String line = reader.readLine();
    while (line != null) 
        StringTokenizer st = new StringTokenizer(line, "\\|");
        while (st.hasMoreTokens()) 
            try 
                Id = Integer.parseInt(st.nextToken());
                Name = st.nextToken();
                EmpId = Integer.parseInt(st.nextToken());
                ServiceId = Integer.parseInt(st.nextToken());

                readableData = new ReadableData(Id,
                        , Name, EmpId,ServiceId);
                     wrO.writeOut(readableData);
                list.add(count, readableData);
                count = count++;
             catch (Exception ex) 
                log.error("Illegal File Format");
                     throw new IllegalFileFormatException("Illegal File Format");
            
             
             line = reader.readLine();
            
         reader.close();
          

【问题讨论】:

【参考方案1】:

使用 asynchronousFileChannel lock() 使用以下代码部分修改您的 Writer 类

byte[] test = printData.getBytes();
        Future<FileLock> featureLock = asynchFileChannel.lock();
        log.info("Waiting for the file to be locked ...");
        FileLock lock = featureLock.get();
        if (lock.isValid()) 
            log.debug(printData);
            Future<Integer> featureWrite = asynchFileChannel.write(
                    ByteBuffer.wrap(test), asynchFileChannel.size());
            log.info("Waiting for the bytes to be written ...");
            int written = featureWrite.get();
            log.info("I’ve written " + written + " bytes into "
                    + file.getFileName() + " locked file!");
            lock.release();
        

【讨论】:

【参考方案2】:

这可能是因为 asynchronousFileChannel 是线程安全的,但 Bytebuffer 不是,应注意确保在操作完成之前不会访问缓冲区。

查看文档http://openjdk.java.net/projects/nio/javadoc/java/nio/channels/AsynchronousFileChannel.html

【讨论】:

尝试这样做,但输出文件中仍然缺少数据。

以上是关于在java中通过asynchronousFileChannel写入时丢失数据的主要内容,如果未能解决你的问题,请参考以下文章

在Java中通过引用传递字符串?

在 Linux 中通过 JAVA 连接 mySQL

在 Java 中通过 post 方法发送表单

在java中通过asynchronousFileChannel写入时丢失数据

如何在java中通过UDP发送一个int

在java中通过TCP发送数据记录