仅使用 Java.IO 从文件读取/写入字节

2024-02-25

在 Java 中,我们如何将字节数组写入文件(并从该文件中读回)?

是的,我们都知道已经有很多这样的问题,但由于完成这项任务的方法有很多,所以它们变得非常混乱和主观。

因此,让我们缩小问题的范围:

Domain:

  • 安卓/Java

我们想要什么:

  • 快(尽可能)
  • 无错误(以严格细致的方式)

我们没有做什么:

  • 第三方库
  • 任何需要 Android API 23 以上的库 (Marshmallow)

(所以,这就排除了阿帕奇共享区 https://commons.apache.org, 谷歌番石榴 https://github.com/google/guava, Java.nio https://en.wikipedia.org/wiki/Non-blocking_I/O_(Java),并留给我们好的 Java.io https://docs.oracle.com/javase/8/docs/api/java/io/package-summary.html)

我们需要的:

  • 经过先写后读的过程后,字节数组始终完全相同(内容和大小)
  • Write方法只需要两个参数:File文件和byte[]数据
  • Read方法返回一个byte[]并且只需要一个参数:File file

在我的特定情况下,这些方法是私有的(不是库)并且是不承担以下责任,(但如果您想创建一个适用于更广泛受众的更通用的解决方案,那就去做吧):

  • 线程安全(文件不会同时被多个进程访问)
  • 文件为空
  • 文件指向不存在的位置
  • 文件位置缺乏权限
  • 字节数组太大
  • 字节数组为空
  • 处理任何“索引”、“长度”或“附加”参数/功能

所以......我们正在寻找最终的防弹代码,未来的人们可以认为可以安全使用,因为你的答案有很多赞成票,并且没有评论说,“这可能会崩溃如果...”

这是我到目前为止所拥有的:

将字节写入文件:

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 :我是否正确,只要提供的文件路径是使用 Android 自己的内部工具派生和/或应用程序经过正确测试,就不会发生这种情况?

IOException :我真的不知道什么会导致这个......但我假设如果确实如此,就没有办法解决它。

因此考虑到这一点......这些方法可以改进或替换吗?如果可以,用什么来改进或替换?


看起来这些将成为必须在 Android API 23 或更高版本上运行的核心实用程序/库方法。

关于库方法,我发现最好不要对应用程序将如何使用这些方法做出任何假设。在某些情况下,应用程序可能希望接受检查IOException(因为文件中的数据必须存在,应用程序才能工作),在其他情况下,应用程序甚至可能不关心数据是否不可用(因为文件中的数据只是缓存,也可以从主源获取)。

当涉及 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 - 这些方法永远不会“没有错误”。
  • 我认为上述方法中不需要/不需要缓冲,因为只完成了一次本机调用 (也可以看看here https://www.androidcookbook.info/android-java/bufferedoutputstream-and-bufferedlnputstream.html).
  • 应用程序现在还可以选择仅读取文件的开头。

为了使应用程序更容易读取文件,可以添加一个附加方法。但请注意,由库来检测任何错误并将其报告给应用程序,因为应用程序本身无法再检测到这些错误。

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.");
    }
}

此实现添加了另一个隐藏的故障点:在创建新数据数组时出现 OutOfMemory。

为了进一步适应应用程序,可以添加其他方法来帮助处理不同的场景。例如,假设应用程序确实不想处理已检查的异常:

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)可以检查文件是否存在、可读且不是太大。应用程序可以在文件读取失败后调用此类函数,并检查无法读取文件的常见原因。写入文件也可以这样做。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

仅使用 Java.IO 从文件读取/写入字节 的相关文章

  • PHP根据给定索引的匹配值合并数组[重复]

    这个问题在这里已经有答案了 我有两个这样的数组 Array1 Array 0 gt Array ID gt 101 Code gt 1075 Date gt 2012 03 03 17 13 12 433 1 gt Array ID gt
  • LibGdx 如何使用 OrthographicCamera 滚动?

    我已经找了 10 个小时 字面意思 我已经完成了 我需要问一下 事情是我正在学习如何使用 LibGdx 来编写 Java 游戏 我正在做一个水平太空飞船游戏 所以 我最糟糕的问题是我不知道如何滚动 我认为绘制会更好地解释 我想绘制一个巨大的
  • android:widgetLayout 和 android:layout 之间的区别?

    我得到一些奇怪的配置 其中 widgetLayout 配置列表项的内部空间 而布局配置整个项目列表和屏幕背景 有人能真正解释一下什么是 widgetLayout 吗 android layout 整个首选项的布局 包括标题 摘要和小部件 a
  • 如何自定义JProgressBar?

    我正在制作一个启动器 我想要一个自定义的进度栏 我已经做了一些研究 并且可以使用 JavaFX 从未用它做过任何事情 并且可以通过替换 UI 来实现 我正在寻找一个具有圆形边缘和圆形填充的酒吧 像这样的事情 package gui impo
  • 使用 Asp.Net 的 GCM 推送通知

    正如您可能已经看到的 Google 正在迁移其推送通知系统 http developer android com guide google gcm c2dm html http developer android com guide goo
  • grails 上的同步块在 Windows 上有效,但在 Linux 上无效

    我有一个 grails 应用程序 它依赖于服务中的同步块 当我在 Windows 上运行它时 同步按预期工作 但当我在 ams linux 上运行时 会出现 StaleObjectStateException 该问题在以下示例中重现 cla
  • android studio logcat 中字母的含义是什么? [复制]

    这个问题在这里已经有答案了 在 android studio 中运行应用程序时 会生成 logcat 并且每行的开头都有字母 这些字母的含义是什么 这些字母表用于各种日志选项 请参阅此链接 日志选项 https developer andr
  • Java G1 GC 处理引用对象运行缓慢

    我已经在 J ava 上运行了计数器 它24小时工作 每秒点击通过100次左右 白天 GC 处理时间从 20 60 毫秒缓慢上升到 10000 60000 毫秒 然后下降到 20 60 毫秒 这种模式不时地重复 从 GC 日志中我发现 GC
  • .class 与 .java

    class 文件和 java 文件有什么区别 我正在尝试让我的小程序工作 但目前我只能在 Eclipse 中运行它 还不能嵌入 HTML 谢谢 编辑 那么如何使用 JVM 进行编译呢 class 文件是编译后的 java 文件 java 都
  • 在 Android 版 Glide 中离线时加载已获取的图像

    我正在使用 Glide 版本 4 8 0 为了加载图像我这样做 GlideApp with HomePageFragment this load remoteURL diskCacheStrategy DiskCacheStrategy A
  • 通用 JSF 实体转换器[重复]

    这个问题在这里已经有答案了 我正在编写我的第一个 Java EE 6 Web 应用程序作为学习练习 我没有使用框架 只是使用 JPA 2 0 EJB 3 1 和 JSF 2 0 我有一个自定义转换器 用于将存储在 SelectOne 组件中
  • 使用 IntelliJ / Android Studio 调试基于 gradle 的单元测试

    我正在使用robolectric gradle 插件 https github com robolectric robolectric gradle plugin为 Android 编写单元测试 到目前为止 除了能够使用 Android S
  • 用 Java 创建迷宫求解算法

    我被分配了用 Java 创建迷宫求解器的任务 这是任务 Write an application that finds a path through a maze The maze should be read from a file A
  • DeadSystemException启动服务Android 7

    在过去的几周里 我在我的事故报告中看到 Fatal Exception java lang RuntimeException Unable to start service com MyService ef705d8 with Intent
  • 有没有办法模拟小部件或屏幕特定位置的触摸?

    我想触摸或点击小部件上的某处 而不让用户在此时明确触摸屏幕 有什么办法可以做到吗 我已经检查了SO答案 有些人建议使用 集成测试 但在未物理或以某种方式连接到笔记本电脑的设备上无法执行 集成测试 无法找到更好的措辞 我还尝试进行 hitTe
  • Android同步onSensorChanged?

    这是我的问题的后续 Android线程可运行性能 https stackoverflow com questions 36395440 android thread runnable performance 我在理解应用程序的同步方法时遇到
  • Java SE + Spring Data + Hibernate

    我正在尝试使用 Spring Data Hibernate 启动 Java SE 应用程序 并且到目前为止已经完成了以下操作 配置文件 Configuration PropertySource classpath hibernate pro
  • 在 Haskell 中增长数组

    我想在 Haskell 中实现以下 命令式 算法 给定一个序列对 e0 s0 e1 s1 e2 s2 en sn 其中 e 和 s 部分不一定是自然数不同的是 在每个时间步都会随机选择该序列的一个元素 例如 ei si 并根据 ei si
  • 将数组从 .npy 文件读入 Fortran 90

    我使用 Python 以二维数组 例如 X 的形式生成一些初始数据 然后使用 Fortran 对它们进行一些计算 最初 当数组大小约为 10 000 x 10 000 时 np savetxt 在速度方面表现良好 但是一旦我开始增加数组的维
  • 如何在Java中跨类共享变量,我尝试了静态不起作用

    类 Testclass1 有一个变量 有一些执行会改变变量的值 现在在同一个包中有类 Testclass2 我将如何访问 Testclass2 中变量的更新值 由 Testclass1 更新 试过这个没用 注意 Testclass1和Tes

随机推荐

  • IE11 + Angular 1.5.11 上奇怪的渲染行为

    我们目前正在 Angular 版本 1 5 11 中开发一个应用程序 现在它已经变得相当大 数百个控制器等 我们偶然发现了 Internet Explorer 11 中的一个问题 一段时间后 有时是几分钟 有时是几个小时 页面开始出现渲染故
  • Visual Studio 无法识别我的网络摄像头激光测距仪代码的 MFC 库

    我尝试直接从互联网复制源代码 但由于下面发现的错误 我无法构建 调试整个文件 请帮忙 Error occurred while restoring NuGet packages System ArgumentException The pa
  • 如何使用 gdb 调试进程而不暂停它?

    我有一个已经在运行的进程 我想用 GDB 调试它 我一直在使用 gdb pid PID 但是 当我这样做时 该过程会暂停 我想附加到进程而不暂停它 并在它仍在运行时在其内存中查看 这可能吗 或者 有没有办法 分叉 该进程 以便我可以查看其内
  • canOpenUrl 失败,但 openUrl 成功

    我面临一个奇怪的问题 我正在使用 xcode 7 2 iOS 9 在真实设备 iphone 4S 不是模拟器 上工作 我有 2 个应用程序 app1 和 app2 app1 应该使用 url 方案将数据发送到 app2 app2已经很好地声
  • 为什么Python中只有主线程可以设置信号处理程序

    在Python的信号处理语义中 只有主线程可以设置信号处理程序 并且只有主线程可以调用信号处理程序 为什么要这样设计呢 此注释出现在 cpython 源文件中信号模块 c https github com python cpython bl
  • 无手拒绝错误:交易查询已完成 - knex、express.js

    我试图首先检查表中的值 如果存在 则删除另一个表中的行并将此新数据插入该表中 我使用了带有 select del 和 insert 命令的事务 db transaction trx gt return trx users where use
  • 没有为实体指定标识符/主键(...)每个实体都必须具有标识符/主键

    I have Peticion实体 但缺少某些内容 因为出现以下错误 No identifier primary key specified for Entity Every Entity must have and identifier
  • cocos2d-x android 设置错误 - java.lang.NullPointerException

    我正在尝试设置适用于 Android 的 cocos2d x我跟着 我通过了终端的步骤 没有任何问题 setup py命令结果符合预期 我的问题是在我设置之后NDK ROOT in C C 构建 环境部分 我得到一些java lang Nu
  • 如何修复猫鼬中的“.create 不是函数”错误

    我正在尝试初始化 Seed js 文件以在我的数据库中启动一些内容 但是当我运行时node bin seed js我不断得到 TypeError Celebrity create is not a function 我已尝试重新安装mong
  • 如何使用滑块同步两个树视图中的滚动

    我正在使用 Visual Studio 2010 C 和 Windows 窗体应用程序 我有两个并排的树视图 并且我已经弄清楚如何使用滚动条上的向上 向下按钮同步滚动 但是当我使用滑块时 它不会移动另一个树视图 我采取了一个有效的列表视图示
  • RxJava,一个可观察多个订阅者:publish().autoConnect()

    我正在使用 rxJava rxAndroid 但有一些非常基本的东西没有按照我的预期运行 我有一个可观察对象和两个订阅者 Observable
  • 它不是附加变量

    我想附加使用上传的文件的名称 POST发布方法 FILES fileImage name 来自 php 脚本 问题是 文件上传后 我没有看到附加的文件名 它只显示空白 为什么文件上传成功后没有附加文件名 如果有人可以提供一个编码示例 那么它
  • 在Python中以空格分割列表中的每个字符串[重复]

    这个问题在这里已经有答案了 我有一个列表 其中包含一个 url 和 Python 中大列表的每个项目中的一些文本 每次出现空格时 我想将每个项目拆分为多个项目 每个项目 2 3 个空格 没有太多代码要发布 它只是目前存储在命名变量中的列表
  • 为什么 julia 无法识别作为函数参数传递的数组类型,而是将其列为 Any?

    我正在 Julia 中定义一个接受向量的函数 具体来说Vector Complex128 当我查看输出时 code warntype我看到变量类型被列为Any 据我了解 这可能会对速度产生影响 这是代码的简单版本 例如 function a
  • 非阻塞 IO 与异步 IO 以及 Java 中的实现

    尝试为自己总结这两个概念之间的区别 因为当我看到人们在一个句子中使用这两个概念时 我真的很困惑 例如 非阻塞异步 IO 我试图弄清楚它是什么意思是 因此 根据我的理解 非阻塞 IO 是操作系统在有任何数据准备好时处理 IO 的主要机制 否则
  • AWS Glue 爬网程序未创建表

    我在 AWS Glue 中创建的爬网程序在成功完成后不会在数据目录中创建表 爬网程序大约需要 20 秒才能运行 日志显示它已成功完成 CloudWatch日志显示 基准 为爬网程序运行启动爬网 基准 分类完成 将结果写入DB 基准 完成写入
  • 使用 Android 设备将实时视频流发送到 wowza 流引擎

    我想将实时视频流从我的 Android 设备发送到 wowza 流引擎 我在此使用示例blog http www walking productions com notslop 2013 01 16 android live streami
  • 使用 IServiceProvider 获取会话服务

    我需要使用 IServiceProvider 访问 ASP NET Core 1 0 中的 ConfigureService 方法中的会话变量 我有一个使用委托 lambda 表达式初始化的服务 可以从任何地方返回值 在此上下文中 此 la
  • Java中的动态方法调度[重复]

    这个问题在这里已经有答案了 以下是关于我的疑问的代码片段 class A void someMethod A param System out println A class C extends A void someMethod C pa
  • 仅使用 Java.IO 从文件读取/写入字节

    在 Java 中 我们如何将字节数组写入文件 并从该文件中读回 是的 我们都知道已经有很多这样的问题 但由于完成这项任务的方法有很多 所以它们变得非常混乱和主观 因此 让我们缩小问题的范围 Domain 安卓 Java 我们想要什么 快 尽