【问题标题】:How to write Queue<T> content to file while Queue is being added to in another class如何在将队列添加到另一个类中时将 Queue<T> 内容写入文件
【发布时间】:2014-04-24 12:45:20
【问题描述】:

我有一个侦听器类,它向队列添加值,我有另一个包含队列并将其写入文件的类。这两个类都在后台线程中运行。

监听类

private AccelerometerQueue mLogQueue; //Queue class implements Runnable
private Thread mQueueThread; //Thread to run Runnable of Queue class
@Override
public void onSensorChanged(SensorEvent sensorEvent) {

    synchronized (this) {
        mLogQueue.addToQueue(
                new AccelerometerVector(
                        System.currentTimeMillis(),
                        sensorEvent.timestamp,
                        sensorEvent.values[0],
                        sensorEvent.values[1],
                        sensorEvent.values[2]
                )
        );


        mQueueThread = new Thread(mLogQueue);
        mQueueThread.start();
    }
}

队列类实现 Runnable 并具有此 LinkedList

public void addToQueue(AccelerometerVector vector) {
    mQueue.add(vector);
}

public synchronized int getQueueSize(){
    return mQueue.size();
}

@Override
public void run() {
    try {
        mLogFile = createLogFile();
        mLogOutStream = new FileOutputStream(mLogFile, true);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }

    while (!mQueue.isEmpty()) {
        try {
            mLogOutStream.write(mQueue.poll().getDataStringLine().getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (mLogFile.length() > AppConstants.LOG_FILE_MAX_SIZE) {
            try {
                reportCurrentLogFileIsFinished(mLogFile);
                mLogOutStream.flush();
                mLogOutStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                mLogOutStream = new FileOutputStream(createLogFile(), true);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
}

private File createLogFile() {

    String datePart = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss").format(new Date());
    String namePart = "log_" + datePart + ".csv";
    File folder = new File(Environment.getExternalStorageDirectory().toString()
            + File.separator + AppConstants.APP_LOG_FOLDER_NAME);

    folder.mkdirs();

    File file = new File(folder + File.separator + namePart);

    if (!file.exists()) { //create the file if not exist
        try {
            file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "Can not create file: " + file.getName());
        }
    }
    if (file.exists()) {
        return file;
    } else {
        return null;
    }
}

我的目标是将队列内容保存到存储中,文件大小不应超过 256kb,当文件达到 256kb 时,应创建一个新文件。

代码当前所做的是写入一些大小为 2 或 3 Kb 的文件,然后在 createLogFile() 方法中引发异常,抱怨无法创建文件(我在 Logcat 中看到了这一点)。

问题是,我做错了什么以及可能的解决方案是什么?

【问题讨论】:

    标签: java android linked-list queue fileoutputstream


    【解决方案1】:

    首先,我假设您使用的是同步集合:

    http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#synchronizedList(java.util.List)

    尝试重新打开文件可能是问题所在。鉴于有一个线程写入文件,我建议您打开文件并保持打开状态。

    最后,你得到了什么例外?

    【讨论】:

    • 我的代码和工作此时没有打开文件操作。我使用的是 LinkedList 而不是 synchronizedlist
    • 这会打开文件:try { mLogOutStream = new FileOutputStream(createLogFile(), true); } catch (FileNotFoundException e) { e.printStackTrace(); }
    • 当列表被多个线程修改时,不同步列表可能会给您带来麻烦。
    • 我在创建新文件时遇到 IOException...我还是想不通!
    • 我也得到 java.io.IOException: write failed: EBADF (Bad file number)
    【解决方案2】:

    好的,我发现了问题。

    第一个问题是我在onSensorChanged 方法中启动了mQueueThread。这导致一个新线程在从onSensorChanged 方法接收更新时启动,并导致内存泄漏或其他一些严重问题。所以我把它移到了构造函数中。

    其次,我将 Queue 类型更改为 ConcurrentLinkedQueue,但我没有任何解释......可能是另一种类型会更好。

    最后,我将Runnable 的实现改成如下:

    @Override
    public void run() {
        while (true) {
            if (mLogOutStream != null && !mQueue.isEmpty()) {
                try {
                    mLogOutStream.write(mQueue.poll().getDataStringLine().getBytes());
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (mLogFile.length() > AppConstants.LOG_FILE_MAX_SIZE) {
                    synchronized (this) {
                        reportCurrentLogFileIsFinished(mLogFile);
                        try {
                            if (mLogOutStream != null) {
                                mLogOutStream.flush();
                                mLogOutStream.close();
                                mLogOutStream = null;
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
    
                        try {
                            mLogFile = createLogFile();
                            mLogOutStream = new FileOutputStream(mLogFile, true);
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
    

    这些更改解决了这些问题。希望这也可以帮助其他人。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-24
      • 1970-01-01
      • 1970-01-01
      • 2013-06-10
      • 2018-04-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多