Java IO

江苏 无锡 缪小东< xmlnamespace prefix ="o" ns ="urn:schemas-microsoft-com:office:office" />

       本篇主要讲述IO相关的内容,主要包括:与IO相关的简单的历史背景知识;Java IO的简单分类;与IO设计相关的两个模式;同时列举几个简单的例子;分析其中几个实现的源代码;最后给大家一些简单扩展的例子。治学先治史,下面我们先从简单的历史开始吧!

 

一、      历史背景

       “对语言设计人员来说,创建好的输入/输出系统是一项特别困难的任务。

――Think in Java

       无论是系统、还是语言的设计中IO的设计都是异常复杂的。面临的最大的挑战一般是如何覆盖所有可能的因素,我们不仅仅要考虑文件、控制台、网络、内存等不同的种类,而且要处理大量的不同的读取方式,如:顺序读取、随机读取,二进制读取、字符读取,按行读取、按字符读取……

       Linux是第一个将设备抽象为文件的操作系统,在Linux中所有的外部设备都可以用读取文件的方法读取,这样编程人员就可以以操作文件的方法操作任何设备。C++IO方面也做了一些改进――引进了流的概念,我们可以通过cincout读写一些对象。Java语言在IO设计方面取得较大的成功,它是完全面向对象的,主要采用装饰器模式避免大量的类,包括了最大的可能性,提供了较好的扩展机制……

       Java库的设计者通过创建大量类来攻克这个难题。事实上,JavaIO系统采用了如此多的类,以致刚开始会产生不知从何处入手的感觉(具有讽刺意味的是,JavaIO设计初衷实际要求避免过多的类)。” 上面一段来自《Think in Java》,确实很多初学者刚刚学习javaIO时会比较茫然,不过等我们知道装饰器模式(Decorator)的用意、场景及其在JavaIO包中的使用,你可能会真正领会整个IOFrameWork

二、IO的分类

    Java IO一般包含两个部分:1.java.io包中堵塞型IO;2.java.nio包中的非堵塞型IO,通常称为New IO。学过操作系统的朋友都知道系统运行的瓶颈一般在于IO操作,一般打开某个IO通道需要大量的时间,同时端口中不一定就有足够的数据,这样read方法就一直等待读取此端口的内容,从而浪费大量的系统资源。有人也许会提出使用java的多线程技术啊!但是在当前进程中创建线程也是要花费一定的时间和系统资源的,因此不一定可取。Java New IO的非堵塞技术主要采用了Observer模式,就是有一个具体的观察者和=监测IO端口,如果有数据进入就会立即通知相应的应用程序。这样我们就避免建立多个线程,同时也避免了read等待的时间。不过本篇主要讲述java的堵塞型IO,就是我们通常应用的那个包。

    打开你的java.io包你可以看到Java的IO包含大量的类和接口(JDK1.6中包含83个类或者接口),如此众多的类和接口似乎无从下手。下面就将IO简单地分类。Java的IO主要包含三个部分:1.流式部分――IO的主体部分;2.非流式部分――主要包含一些辅助流式部分的类,如:File类、RandomAccessFile类和FileDescriptor等类;3.文件读取部分的与安全相关的类,如:SerializablePermission类。以及与本地操作系统相关的文件系统的类,如:FileSystem类和Win32FileSystem类和WinNTFileSystem类。

       流式部分可以概括为:两个对应一个桥梁。两个对应指:1.字节流(Byte Stream)和字符流(Char Stream)的对应;2.输入和输出的对应。一个桥梁指:从字节流到字符流的桥梁。对应于输入和输出为InputStreamReaderOutputStreamWriter

       在流的具体类中又可以具体分为:1.介质流(Media Stream或者称为原始流Raw Stream)――主要指一些基本的流,他们主要是从具体的介质上,如:文件、内存缓冲区(Byte数组、Char数组、StringBuffer对象)等,读取数据;2.过滤流(Filter Stream)――主要指所有FilterInputStream/FilterOutputStreamFilterReader/FilterWriter的子类,主要是对其包装的类进行某些特定的处理,如:缓存等。

 

三、IO中的流

       流具有最基本的特点:“One dimension , one direction . 即流是一维的,同时流是单向的。关于维和我们通常说的一维长度,二维平面,三维空间,四维时空……是同一个概念,流就是一维的。单向就是只可以一个方向(按顺序从头至尾依次)读取,不可以读到某个位置,再返回前面某个位置。流的概念和实际水流的概念基本一致,水只可以从高向低一个方向流动。我们某时在目地喝了一口水,下次在同一个地点喝水已经不是当时的那片水了。

       流的这种特性在JMSJava Message Service)的API设计中得到了体现。JMSJ2EE平台下面向消息中间件的一个标准。(关于中间件技术有机会和大家探讨)JMS中有五种具体类型的消息,这些消息一般分为两类:1.流式的消息――包含ByteMessageStreamMessage2.非流式的消息――包含TextMessageObjectMessageMapMessage。我们在明白IO中流的特点后,基本可以明白JMS API设计者的意图。

       可能有些场合我们需要在文件中随机插入数据、在流中来来回回地执行某些操作,这时候我们绝对不可以使用流相关的对象。很幸运JDK的设计者为我们设计了一个单独的类RandomAccessFile,它可以完成打开、关闭文件、以基本数据类型的方式读取数据、读取下一个行、以UTF等格式读取数据、写入各种类型的数据、比较特殊的是他可以通过文件指针的seek方法让文件指针移到某个位置,可以通过getFilePointer()方法得到当前指针的位置、可以通过length()方法得到当前文件的容量、通过getFD()得到FileDescriptor对象,通过getChannel()方法得到FileChannel对象,从而和New IO整合。

       下面比较简单的分析IO中的各个对象吧!

3.1 IO中的输入字节流

       下面是IO中输入字节流的继承图。

o        InputStream

o        ByteArrayInputStream

o        FileInputStream

o        FilterInputStream

o        BufferedInputStream

o        DataInputStream

o        LineNumberInputStream

o        PushbackInputStream

o        ObjectInputStream

o        PipedInputStream

o        SequenceInputStream

o        StringBufferInputStream

在上面的关系图中可以看出:1.InputStream是所有的输入字节流的父类,它是一个抽象类。2. ByteArrayInputStreamStringBufferInputStreamFileInputStream是三种基本的介质流,它们分别将Byte数组、StringBuffer、和本地文件中读取数据。PipedInputStream是从与其它线程共用的管道中读取数据,与Piped相关的知识会用专门的一小节讲解。3. ObjectInputStream和所有FilterInputStream的子类都是装饰流(装饰器模式的主角)。下表列出了这些流的功能及如何使用它们(具体使用在讲解完装饰器模式后会举几个例子)。

基本输入字节流:

功能

如何构造

怎样使用

ByteArrayInputStream

将内存中的Byte数组适配为一个InputStream

从内存中的Byte数组创建该对象(2种方法)

一般作为数据源,会使用其它装饰流提供额外的功能,一般都建议加个缓冲功能。

StringBufferInputStream

将内存中的字符串适配为一个InputStream

从一个String对象创建该对象。底层的实现使用StringBuffer。该类被Deprecated。主要原因是StringBuffer不应该属于字节流,所以推荐使用StringReader

一般作为数据源,同样会使用其它装饰器提供额外的功能。

FileInputStream

最基本的文件输入流。主要用于从文件中读取信息。

通过一个代表文件路径的StringFile对象或者FileDescriptor对象创建。

一般作为数据源,同样会使用其它装饰器提供额外的功能。

PipedInputStream

读取从对应PipedOutputStream写入的数据。在流中实现了管道的概念。

利用对应的PipedOutputStream创建。

在多线程程序中作为数据源,同样会使用其它装饰器提供额外的功能。

SequenceInputStream

2个或者多个InputStream 对象转变为一个InputStream.

使用两个InputStream 或者内部对象为InputStream Enumeration对象创建该对象。

一般作为数据源,同样会使用其它装饰器提供额外的功能。

FilterInputStream

给其它被装饰对象提供额外功能的抽象类

主要子类见下表

 

装饰、输入字节流:

功能

如何构造

怎样使用

DataInputStream

一般和DataOutputStream配对使用,完成基本数据类型的读写。

利用一个InputStream构造。

提供了大量的读取基本数据类新的读取方法。

BufferedInputStream

使用该对象阻止每次读取一个字节都会频繁操作IO。将字节读取一个缓存区,从缓存区读取。

利用一个InputStream、或者带上一个自定义的缓存区的大小构造。

使用InputStream的方法读取,只是背后多一个缓存的功能。设计模式中透明装饰器的应用。

LineNumberInputStream

跟踪输入流中的行号。可以调用getLineNumber( )setLineNumber(int)方法得到和设置行号。

利用一个InputStream构造。

紧紧增加一个行号。可以象使用其它InputStream一样使用。

PushbackInputStream

可以在读取最后一个byte 后将其放回到缓存中。

利用一个InputStream构造。

一般仅仅会在设计compilerscanner 时会用到这个类。在我们的java语言的编译器中使用它。很多程序员可能一辈子都不需要。

3.2 IO中的输出字节流

       下面是IO中输出字节流的继承图。

    • OutputStream
      • ByteArrayOutputStream
      • FileOutputStream
      • FilterOutputStream
        • BufferedOutputStream
        • DataOutputStream
        • PrintStream
      • ObjectOutputStream
      • PipedOutputStream

在上面的关系图中可以看出:1.OutputStream是所有的输出字节流的父类,它是一个抽象类。2. ByteArrayOutputStreamFileOutputStream是两种基本的介质流,它们分别向Byte数组、和本地文件中写入数据。PipedOutputStream是向与其它线程共用的管道中写入数据, 3. ObjectOutputStream和所有FilterOutputStream的子类都是装饰流。下表列出了输出字节流的功能及如何使用它们。

功能

如何构造

怎样使用

ByteArrayOutputStream

在内存中创建一个buffer。所有写入此流中的数据都被放入到此buffer中。

无参或者使用一个可选的初始化buffer的大小的参数构造。

一般将其和FilterOutputStream套接得到额外的功能。建议首先和BufferedOutputStream套接实现缓冲功能。通过toByteArray方法可以得到流中的数据。(不通明装饰器的用法)

FileOutputStream

将信息写入文件中。

使用代表文件路径的StringFile对象或者 FileDescriptor对象创建。还可以加一个代表写入的方式是否为append的标记。

一般将其和FilterOutputStream套接得到额外的功能。

PipedOutputStream

任何写入此对象的信息都被放入对应PipedInputStream 对象的缓存中,从而完成线程的通信,实现了“管道”的概念。具体在后面详细讲解。

利用PipedInputStream构造

在多线程程序中数据的目的地的。一般将其和FilterOutputStream套接得到额外的功能。

FilterOutputStream

实现装饰器功能的抽象类。为其它OutputStream对象增加额外的功能。

见下表

见下表

       装饰输出字节流:

功能

如何构造

怎样使用

DataOutputStream

通常和DataInputStream配合使用,使用它可以写入基本数据类新。

使用OutputStream构造

包含大量的写入基本数据类型的方法。

PrintStream

产生具有格式的输出信息。(一般地在java程序中DataOutputStream用于数据的存储,即J2EE中持久层完成的功能,PrintStream完成显示的功能,类似于J2EE中表现层的功能)

使用OutputStream和一个可选的表示缓存是否在每次换行时是否flush的标记构造。还提供很多和文件相关的构造方法。

一般是一个终极(“final”)的包装器,很多时候我们都使用它!

BufferedOutputStream

使用它可以避免频繁地向IO写入数据,数据一般都写入一个缓存区,在调用flush方法后会清空缓存、一次完成数据的写入。

从一个OutputStream或者和一个代表缓存区大小的可选参数构造。

提供和其它OutputStream一致的接口,只是内部提供一个缓存的功能。

 

3.3字节流的输入与输出的对应

       3.1节讲过输入与输出的对应,下图表示字节流部分的输入与输出的对应关系。 

 Java IO 全攻略---之一 - master24 - master24

 

       上图中蓝色的为主要的对应部分,红色的部分就是不对应部分。我习惯上称之为“不入流”部分。紫色的虚线部分代表这些流一般要搭配使用。从上面的图中可以看出Java IO中的字节流是极其对称的。

“存在及合理”我们看看这些字节流中不太对称的几个类吧!

1.         LineNumberInputStream主要完成从流中读取数据时,会得到相应的行号,至于什么时候分行、在哪里分行是由改类主动确定的,并不是在原始中有这样一个行号。在输出部分没有对应的部分,我们完全可以自己建立一个LineNumberOutputStream,在最初写入时会有一个基准的行号,以后每次遇到换行时会在下一行添加一个行号,看起来也是可以的。好像更不入流了。

2.         PushbackInputStream的功能是查看最后一个字节,不满意就放入缓冲区。主要用在编译器的语法、词法分析部分。输出部分的BufferedOutputStream几乎实现相近的功能。

3.         StringBufferInputStream已经被Deprecated,本身就不应该出现在InputStream部分,主要因为String应该属于字符流的范围。已经被废弃了,当然输出部分也没有必要需要它了!还允许它存在只是为了保持版本的向下兼容而已。

4.         SequenceInputStream可以认为是一个工具类,将两个或者多个输入流当成一个输入流依次读取。完全可以从IO包中去除,还完全不影响IO包的结构,却让其更“纯洁”――纯洁的Decorator模式。

5.         PrintStream也可以认为是一个辅助工具。主要可以向其他输出流,或者FileInputStream写入数据,本身内部实现还是带缓冲的。本质上是对其它流的综合运用的一个工具而已。一样可以踢出IO包!System.outSystem.out就是PrintStream的实例!

蓝色的部分是IO字节流的主要组成部分,存在极强的对称关系。关于搭配使用的三对类补充一下:ObjectInputStream/ObjectOutputStreamDataInputStream/DataOutputStream主要是要求写对象/数据和读对象/数据的次序要保持一致,否则轻则不能得到正确的数据,重则抛出异常(一般会如此)PipedInputStream/PipedOutputStream在创建时一般就一起创建,调用它们的读写方法时会检查对方是否存在,或者关闭!道理极其简单――对方都不在了,怎么交互啊!


3.4 字节流与字符流

       从上面我们可以看出IO中的字节流是极其复杂的,存在大量的类,到目前为止还没有真正使用它们,使用它们应该也是极其复杂的吧!JDK1.1SunIO库进行了重大的改进。看到ReaderWriter类时,大多数人的第一个感觉(不要太相信感觉哦!感觉也许会欺骗你的!)就是它们是用来替换原来的InputStreamOutputStream类。有新的类,干吗还使用旧的呢!?但实情并非如此。尽管Sun不建议使用原始的流库中的某些功能,但原来的流依然得到了保留,不仅为了保持向后兼容,主要原因是新库不是旧库的替代,而是对旧库的增强。从以下两点可以明显地看出:

(1) 在老式的类层次结构里加入了新的类,这表明 Sun公司没有放弃老式流库的意图。

(2) 在许多情况下,新库中类的使用需要联合老结构中的类。为达到这个目的,需要使用一些“桥”类,如:InputStreamReader将一个InputStream转换成ReaderOutputStreamWriter将一个OutputStream转换成Writer

那么Sun为什么在Java 1.1里添加了ReaderWriter层次,最重要的原因便是国际化(Internationalization――i18n)的需求。老式IO流层次结构只支持8位字节流,不能很好地控制16位的Unicode字符。Java本身支持UnicodeSun又一致吹嘘其支持Unicode,因此有必要实现一个支持Unicode的流的层次结构,所以出现了ReaderWriter层次,以提供对所有IO操作中的Unicode的支持。除此之外,新库也对速度进行了优化,可比旧库更快地运行。

8位的字节流和16位的字符流的对应关系,可以从ByteInputStream/ByteOutputStreamCharArrayInputStream/CharArrayOutputStream的对应关系中看出端倪。(还没看出来啊!赶紧去看看Java的基本数据类型)。

因此在JavaIO体系中存在字节流和字符流的对应关系。下面就看看字符流吧!

3.5 IO中的输入字符流

       下面是IO中输入字符流的继承图。

    • Reader
      • BufferedReader
        • LineNumberReader
      • CharArrayReader
      • FilterReader
        • PushbackReader
      • InputStreamReader
        • FileReader
      • PipedReader
      • StringReader

在上面的关系图中可以看出:1.Reader是所有的输入字符流的父类,它是一个抽象类。2.CharReaderStringReader是两种基本的介质流,它们分别将Char数组、String中读取数据。PipedReader是从与其它线程共用的管道中读取数据。3. BufferedReader很明显就是一个装饰器,它和其子类负责装饰其它Reader对象。4.FilterReader是所有自定义具体装饰流的父类,其子类PushbackReaderReader对象进行装饰,会增加一个行号。5.InputStreamReader是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream转变为Reader的方法。我们可以从这个类中得到一定的技巧。

       Reader中各个类的用途和使用方法基本和InputStream中的类使用一致。后面会有ReaderInputStream的对应关系。

3.6 IO中的输出字符流

下面是IO中输出字符流的继承图。

    • Writer
      • BufferedWriter
      • CharArrayWriter
      • FilterWriter
      • OutputStreamWriter
        • FileWriter
      • PipedWriter
      • PrintWriter
      • StringWriter

在上面的关系图中可以看出:1.Writer是所有的输出字符流的父类,它是一个抽象类。2. CharArrayWriterStringWriter是两种基本的介质流,它们分别向Char数组、String中写入数据。PipedWriter是向与其它线程共用的管道中写入数据, 3. BufferedWriter是一个装饰器为Writer提供缓冲功能。4.PrintWriterPrintStream极其类似,功能和使用也非常相似。5.OutputStreamWriterOutputStreamWriter转换的桥梁,它的子类FileWriter其实就是一个实现此功能的具体类(具体可以研究一下Source Code)。功能和使用和OutputStream极其类似,后面会有它们的对应图。

3.7字符流的输入与输出的对应

下图为字符流的输入与输出的对应关系图:

 

 

       对应关系和字节流的输入输出基本一致,不必多说了吧!在下面的源代码阅读部分会仔细研究一些!

3.8字节流和字符流的对应

       JavaIO中存在输入、输出的对应和字节流和字符流的对应,下面就看看字节流和字符流的对应吧!

3.8.1输入的对应

       下图是IO中字节输入流与字符输入流的对应图:

 

 

       蓝色的表示对应的部分,红色的表示不对应的部分。至于为什么不对应还是你自己多看看源代码、多考虑考虑吧!还要强调一点就是即使对应,它们的继承关系也是不太对应的。

 

3.8.2输出的对应

下图是IO中字节输出流与字符输出流的对应图:

 

 

       不多说了!等讲述了AdapterDecorator模式会基本明白IO架构的!通过几个实例一般就可以使用了!


<think>好的,我现在需要处理用户关于Java IO的问题。用户希望了解Java IO的概念或者解决相关问题,特别是询问教程和故障排除的方法。首先,我得回顾一下Java IO的基础知识,确保自己理解正确,然后组织回答的结构。 首先,Java IO主要涉及输入输出流,用于处理数据的读写。核心包是java.io,里面有很多类,比如File、InputStream、OutputStream、Reader、Writer等。用户可能需要知道这些类的层次结构和使用方法。 接下来,常见的IO操作包括文件读写、网络通信、序列化等。比如,FileInputStream和FileOutputStream用于字节流,而FileReader和FileWriter用于字符流。缓冲流(BufferedInputStream等)可以提高效率,这部分应该提到。 然后,异常处理是Java IO中很重要的一部分,比如IOException,需要正确处理try-with-resources来自动关闭流,避免资源泄漏。这部分用户可能在故障排除时会遇到问题,比如未正确关闭流导致文件锁定或资源耗尽。 关于教程,Oracle的官方文档是权威资源,应该引用。比如引用[3]提到了JSP的信息,但用户需要的是IO的教程,可能需要检查是否有其他引用相关。不过用户给出的引用中,引用[1]是关于JDK 7的故障排除工具,可能和调试IO问题相关,比如使用jdb进行调试。引用[5]提到字节码信息,可能和IO关系不大,但故障排除时可能需要查看异常堆栈,这可能涉及字节码或类加载的问题。 对于故障排除,常见问题包括文件路径错误、权限问题、字符编码不一致导致的乱码,或者流未正确关闭。比如,文件找不到可能是因为相对路径的当前工作目录与预期不符,或者文件被其他进程占用。这时候需要检查路径是否正确,是否有读取权限,使用绝对路径测试,或者使用工具如Process Explorer查看文件句柄。 此外,NIO(New IO)在Java 1.4引入,提供了非阻塞IO和通道等高效处理方式,用户可能也需要了解NIO和传统IO的区别,比如使用Channel和Buffer的方式,或者使用Files类简化操作。 在组织回答时,需要分步骤讲解,比如先介绍核心概念,然后常见操作,接着是故障排除技巧,最后提供学习资源和相关工具。同时,生成的问题要围绕Java IO的进一步学习,比如NIO、性能优化、常见异常处理等。 需要确保回答中的LaTeX格式正确,比如类名和方法名可能需要用代码块,而数学表达式则用$...$。例如,文件路径的转义可能需要讨论,比如在字符串中使用反斜杠需要转义,写成`"C:\\\\path\\\\to\\\\file"`,但这里可能不需要数学表达式,所以可能不需要用到LaTeX的公式部分。 检查用户提供的引用,是否有与IO相关的资源。引用[4]是关于安卓USB驱动的,可能不相关。引用[2]关于反射,可能也不直接相关,但故障排除时可能会用到反射来检查类路径或资源加载,这可能间接相关,但可能不需要特别提到。 总结回答结构: 1. Java IO核心概念:流、字节流与字符流、缓冲流、NIO。 2. 常见操作:文件读写示例代码。 3. 故障排除:常见问题及解决方法,如路径、权限、编码、资源泄漏。 4. 学习资源:官方教程、工具(如jdb)。 5. 相关问题:如何选择IO和NIO,处理大文件,字符编码问题,关闭资源方法,常见异常处理。 需要确保回答中的引用正确,比如引用[1]关于JDK工具,可能在故障排除时使用jdb或者jstack等工具分析问题,可以提到。引用[3]的链接虽然是JSP,但Oracle的Java EE教程可能包含IO相关内容,需要检查链接是否有效,但用户提供的链接可能已失效,需要注意。不过用户给出的引用可能有误,比如引用[3]的网址是javaee.github.io,可能是正确的,但需要确认是否有IO相关部分。 最后,代码示例需要正确,比如使用try-with-resources来读取文件,展示正确的异常处理方式。同时,确保所有技术术语准确,例如InputStreamReader处理字符编码,BufferedReader提高读取效率。 可能的问题点:用户提供的引用中是否有直接关于Java IO的内容?引用[1]提到JDK工具,可以用于调试IO问题,比如使用jdb调试应用程序,或者在出现IO异常时分析线程状态。引用[5]关于字节码信息,可能与IO问题关系不大,但类加载时找不到资源文件可能会涉及,需要看具体情况。 因此,在故障排除部分,可以建议使用JDK工具如jstack检查是否有线程阻塞在IO操作,或者使用jdb进行调试,引用[1]。同时,处理资源泄漏时,可以使用try-with-resources来自动关闭流,这是Java 7的特性,可能需要提到。 综上所述,回答的结构应该是先介绍核心概念,然后示例代码,接着故障排除步骤,引用相关资源,最后生成相关问题。</think>### Java IO 概念与问题排查指南 #### 一、核心概念 Java IO(输入输出)用于处理数据读写,核心包为 `java.io`,主要分为两类: 1. **字节流**:处理二进制数据,基类为 `InputStream` 和 `OutputStream`,例如 `FileInputStream` 和 `BufferedOutputStream`。 2. **字符流**:处理文本数据,基类为 `Reader` 和 `Writer`,例如 `FileReader` 和 `BufferedWriter`。 3. **NIO(New IO)**:Java 1.4 引入,通过 `Channel` 和 `Buffer` 实现高效非阻塞操作,例如 `Files.readAllLines()`[^1]。 #### 二、常见操作示例 1. **文件读取(字符流)**: ```java try (BufferedReader reader = new BufferedReader(new FileReader("test.txt"))) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } ``` 2. **文件写入(字节流)**: ```java try (OutputStream out = new BufferedOutputStream(new FileOutputStream("output.dat"))) { out.write("Hello".getBytes()); } catch (IOException e) { e.printStackTrace(); } ``` #### 三、故障排查技巧 1. **文件路径问题** - 使用绝对路径或检查工作目录:`System.getProperty("user.dir")`。 - 路径分隔符兼容性:使用 `File.separator` 替代硬编码的 `/` 或 `\`。 2. **权限与资源占用** - 确认文件可读/写:`file.canRead()` 和 `file.canWrite()`。 - 确保流正确关闭:使用 **try-with-resources**(Java 7+)避免资源泄漏。 3. **字符编码问题** - 指定编码格式:例如 `new InputStreamReader(new FileInputStream("file.txt"), StandardCharsets.UTF_8)`。 4. **调试工具** - 使用 `jdb`(Java Debugger)追踪 IO 异常堆栈[^1]。 - 通过 `jstack` 分析线程阻塞(如网络 IO 超时)。 #### 四、学习资源 1. **官方教程** - [Oracle Java IO 教程](https://docs.oracle.com/javase/tutorial/essential/io/)(涵盖基础与 NIO)。 2. **进阶内容** - Java NIO.2(Java 7+)的 `Path` 和 `Files` 类[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值