读写字节从文件的使用仅Java。IO

0

的问题

我们怎么能写字节列于文件(读它从文件)中Java?

是的,我们都知道已经有很多这样的问题,但他们非常混乱和主观的,事实上,由于有这么多的方式完成这项任务。

因此,让我们降低范围的问题:

域:

  • 安卓/Java

我们想要什么:

  • 快(尽可能)
  • 错误(在一刚性细致的方式)

什么我们不做的事情:

  • 第三方图书馆
  • 任何库,需要安卓API后来于23(棉花)

(因此,这一规则出 Apache Commons, 谷歌番石榴, Java。仁王,给我们留下了 良好的ol'Java。io)

我们需要:

  • 字节列总是完全相同(内容和大小)后通过的写-那么-读过程
  • 写信的方法仅仅要求两个参数:文件的文件,并字节[]中的数据
  • 读取的方法返回字节[]并且只需要一个参数:文件的文件

在我的特别情况下,这些方法是私人(不是图书馆)并且是 不负责以下,(但如果您想要创造一个更普遍的解决方案,适用于一个更广泛的受众,去吧):

  • 线的安全(文件将不会被访问超过一个进程一旦)
  • 文件正在null
  • 文件指向不存在的位置
  • 缺乏权限文件中的位置
  • 字阵列在太大
  • 字节列正在null
  • 处理任何与"索引,""长度"或"追加"的参数/能力

所以...我们在搜索的最终防弹的代码,人们在未来可以假定安全使用因为你的答案有很多的选民,也没有评论说,"这可能会崩溃,如果..."

这是我迄今为止:

写字节的文件:

private void writeBytesToFile(final File file, final byte[] data) {
        try {
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(data);
            fos.close();
        } catch (Exception e) {
            Log.i("XXX", "BUG: " + e);
        }
    }

读字节从文件:

private byte[] readBytesFromFile(final File file) {
        RandomAccessFile raf;
        byte[] bytesToReturn = new byte[(int) file.length()];
        try {
            raf = new RandomAccessFile(file, "r");
            raf.readFully(bytesToReturn);
        } catch (Exception e) {
            Log.i("XXX", "BUG: " + e);
        }
        return bytesToReturn;
}

从我读,可能的例外是:

FileNotFoundException:我是正确的,这不应该发生,因为只要的文件路径正在提供的是衍生于使用机器的自己的内部工具和/或如果应用程序进行了测试,正确吗?

IOException:我真的不知道什么可以引起这...但我猜想有没有办法绕过它,如果它。

因此,考虑...可以这些方法可以改进或更换,如果是这样,什么?

android arrays file java
2021-11-23 02:58:43
2

最好的答案

6

它看起来像这些都将是核心实用工具/图书馆的方法,这必须运行在安卓API23或以后。

关于图书馆的方法,我觉得最好不作任何假设上是如何应用程序将使用这些方法。 在某些情况下的应用可能需要接受检查 IOExceptions(因为文件中的数据必须存在的应用程序的工作),在其它情况下的应用可能甚至不在乎如果未提供数据(由于数据从一个文件只是缓存,也可以从一个主要来源)。

当涉及到I/O操作,没有保证,操作将取得成功(例如用户丢的手机在厕所). 该图书馆应当反映,并给予应用程序选择如何处理错误。

优化I/O性能总是假定的"快乐的道路",并抓错误图找出哪里出了问题。 这是反直觉的正常程,但必须在处理与储存I/O.例如,只是检查文件是否存在之前读一个文件可以让你用两次为缓慢--所有这些种类的I/O行动加起来快慢你的应用程序下来。 只是假设的文件存在,如果你得到错误的,只有这样,检查文件是否存在。

所以,鉴于这些想法,主要职能如下:

public static void writeFile(File f, byte[] data) throws FileNotFoundException, IOException {
    try (FileOutputStream out = new FileOutputStream(f)) {
        out.write(data);
    }
}

public static int readFile(File f, byte[] data) throws FileNotFoundException, IOException {
    try (FileInputStream in = new FileInputStream(f)) {
        return in.read(data); 
    }
}

注意到有关执行情况:

  • 该方法还可以扔运行时-异常喜欢 NullPointerExceptions-这些方法永远不会被"错误"。
  • 我不认为缓冲所需要/要在方法上,因为只有一个当地叫做 (见也 在这里).
  • 该应用程序现在还有选择只读开始时文件。

来使它更易于申请阅读一个文件,一个额外方法可以增加。 但注意,这是图书馆,以检测任何错误,并报告它们的应用由于应用程序本身不可能再检测这些错误。

public static byte[] readFile(File f) throws FileNotFoundException, IOException {
    int fsize = verifyFileSize(f);
    byte[] data = new byte[fsize];
    int read = readFile(f, data);
    verifyAllDataRead(f, data, read);
    return data;
}

private static int verifyFileSize(File f) throws IOException {
    long fsize = f.length();
    if (fsize > Integer.MAX_VALUE) {
        throw new IOException("File size (" + fsize + " bytes) for " + f.getName() + " too large.");
    }
    return (int) fsize;
}

public static void verifyAllDataRead(File f, byte[] data, int read) throws IOException {
    if (read != data.length) {
        throw new IOException("Expected to read " + data.length 
                + " bytes from file " + f.getName() + " but got only " + read + " bytes from file.");
    }
}

这个执行增加了另一个隐藏的故障点:内存在的新的阵列数据是创建。

容纳的应用程序进一步,另外的方法可以加入有助于与不同方案。 例如,我们说的应用程序真的很不想处理检查的情况除外:

public static void writeFileData(File f, byte[] data) {
    try {
        writeFile(f, data);
    } catch (Exception e) {
        fileExceptionToRuntime(e);
    }
}

public static byte[] readFileData(File f) {
    try {
        return readFile(f);
    } catch (Exception e) {
        fileExceptionToRuntime(e);
    }
    return null;
}

public static int readFileData(File f, byte[] data) {
    try {
        return readFile(f, data);
    } catch (Exception e) {
        fileExceptionToRuntime(e);
    }
    return -1;
}

private static void fileExceptionToRuntime(Exception e) {
    if (e instanceof RuntimeException) { // e.g. NullPointerException
        throw (RuntimeException)e;
    }
    RuntimeException re = new RuntimeException(e.toString());
    re.setStackTrace(e.getStackTrace());
    throw re;
}

该方法 fileExceptionToRuntime 是最小的实施,但它表示的想法在这里。

图书馆还可以帮助应用程序,排除故障时,一个错误不会发生。 例如,一种方法 canReadFile(File f) 可以检查文件是否存在和是可读的,并不太大。 该申请可能称这种功能后文件阅读障和检查的常见原因为什么一个文件无法阅读。 同样可以做到用于编写文件。

2021-11-28 22:59:55

更好的有益和翔实的答案。 我把它放在一起的一个项目,看看如果我可以更好地理解它。 是什么原因改变的readBytes方法的签名从我有什么? (你需要一个字节[]作为一个参数和返回int)。 还是你最后一块代码旨在将部分图书馆或应用程序?
Nerdy Bunz

还不行"返回(int)f。长();"的崩溃,因为f。长度是比较大的整数。MAX_VALUE?
Nerdy Bunz

@NerdyBunz关于最后一个问题:没有,"向下转换"不给一个错误,并在这种情况下,IOException时引发的 fsize 值过大。 此外,我应该重复使用 fsize 那里(由于 f.length() 结果在一个I/O操作)。
vanOekel

关于第一个问题:它的目的是将一部分的图书馆。 我 byte[] readFile(File f) 类似于你的 byte[] readBytesFromFile(final File file). 我 byte[] readFileData(File f) 方法是一个例子可以如何定义这些职能进一步。 我有麻烦找出哪些方法让(public)和保持隐藏(private),我认为这是一个问题,只有你可以回答:哪些方法做你想要应用程序的使用没有受到限制的应用程序?
vanOekel
3

虽然你不能使用第三方图书馆,你仍然可以读出他们的代码并学习他们的经验。 在谷歌的番石榴例如,通常阅读一个文件进字节是这样的:

FileInputStream reader = new FileInputStream("test.txt");
byte[] result = ByteStreams.toByteArray(reader);

核心实施的这是 toByteArrayInternal. 以前叫这个,你应该检查:

  • "Not null"文件是过去了(异常)
  • 该文件存在(FileNotFoundException)

在这之后,它降低到处理的一个输入流和这里IOExceptions。 阅读时流了很多事情无法控制的应用程序可以去错误的(不良的部门和其它硬件的问题,《仲裁示范法》第运作良好的司机,操作系统的访问权限)和表现自己与IOException.

我在这里复制的执行情况:

private static final int BUFFER_SIZE = 8192;

/** Max array length on JVM. */
private static final int MAX_ARRAY_LEN = Integer.MAX_VALUE - 8;

private static byte[] toByteArrayInternal(InputStream in, Queue<byte[]> bufs, int totalLen)
      throws IOException {
    // Starting with an 8k buffer, double the size of each successive buffer. Buffers are retained
    // in a deque so that there's no copying between buffers while reading and so all of the bytes
    // in each new allocated buffer are available for reading from the stream.
    for (int bufSize = BUFFER_SIZE;
        totalLen < MAX_ARRAY_LEN;
        bufSize = IntMath.saturatedMultiply(bufSize, 2)) {
      byte[] buf = new byte[Math.min(bufSize, MAX_ARRAY_LEN - totalLen)];
      bufs.add(buf);
      int off = 0;
      while (off < buf.length) {
        // always OK to fill buf; its size plus the rest of bufs is never more than MAX_ARRAY_LEN
        int r = in.read(buf, off, buf.length - off);
        if (r == -1) {
          return combineBuffers(bufs, totalLen);
        }
        off += r;
        totalLen += r;
      }
    }

    // read MAX_ARRAY_LEN bytes without seeing end of stream
    if (in.read() == -1) {
      // oh, there's the end of the stream
      return combineBuffers(bufs, MAX_ARRAY_LEN);
    } else {
      throw new OutOfMemoryError("input is too large to fit in a byte array");
    }
  }

正如你可以看到大多数的逻辑,有与阅读该文件在大块。 这是处理的情况,在那里你不知道的尺寸的输入流,在开始阅读。 在你的情况下,只需要阅读文件和您应该能知道的长度,因此这种复杂性是可以避免的。

其他检查OutOfMemoryException. 在标准Java的限制太大,然而在安卓,这将是一个小得多的价值。 你应该检查之前,试图阅读该文件,没有 足够的存储器可用的.

2021-11-26 13:42:23

其他语言

此页面有其他语言版本

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................