目录
InputStream类是基本的输入类。它定义了所有输入流所需的方法。
字节流
- Java把不同类型的输入、输出抽象为流stream,分为输入流和输出流,用统一的接口来表示
- Java开发环境中提供了包java.io,其中包括一系列的类来实现输入/输出处理
- InputStream是所有字节输入流的祖先,而OutputStream是所有字节输出流的祖先
public abstract class InputStream implements Closeable
public abstract class OutputStream implements Closeable, Flushable
具体子类:ByteArrayInputStream, FileInputStream, FilterInputStream, ObjectInputStream,
InputStream
- int read()
- int read(byte[])
- int read(byte[],int,int)
- void close()关闭流
- int available()报告流中直接可读的字节数
- skip(long)跳过流中指定的字节
练习1:使用字节流读取一个文本文件,并显示其内容
package com.yan1;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class Test1 {
public static void main(String[] args) throws Exception {
try (OutputStream os = new FileOutputStream("d:/out/abc.txt")) {//这是我的查找文件夹
String ss="abcdef中国人民解放军";
byte[] arr=ss.getBytes();
for(byte kk:arr)
os.write(kk);
}
}
}
OutputStream
- void write(int)
- void write(byte[])
- void write(byte[],int,int)
- void close() 关闭输出流
- void flush() 强行将写入缓冲区中剩余的数据写入
File file = new File("d:\\FileTest.java");
if (file.exists()) {
try (InputStream is = new FileInputStream(file);) {
byte[] buffer = new byte[8192];
int len = is.read(buffer);
while (len > 0) {
System.out.write(buffer, 0, len);
len = is.read(buffer);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
InputSream和OutputStream中定义了read()和write()方法,它们被派生流类重载。字节流是字节序列,它与外部设备中的字节存在着一一对应的关系,不存在字符的转换,被读写字节的个数与外部设备中的字节个数是相同的
基本输入输出方法
- System类不能创建对象,也就是说,System类的所有属性和方法都是静态的,引用时要以System作为前缀
- System.in与System.out是System类的两个静态属性,分别对应了系统的标准输入/输出流
- System.out:把输出送到缺省的显示(通常是显示器),是PrintStream的对象
- System.in:从标准输入获取输入(通常是键盘),是InputStream的对象
- System.err:把错误信息送到缺省的显示,是PrintStream的对象
package com.yan4;
import java.io.IOException;
/*
* 题目:用户在键盘依次输入若干个数字,每输入一个数字都需要按回车键确认,
* 最后在键盘输入一个非数字字符串结束整个输入操作过程。
* 程序将计算出这些数的和以及平均值。
*/
public class Test1 {
public static void main(String[] args) throws IOException {
int sum = 0;
int count = 0;
while (true) {
String ss = readData();
System.out.println("input:" + ss);
if ("quit".equals(ss))
break;
if (ss != null && ss.trim().length() > 0) {
int kk = Integer.parseInt(ss);
sum += kk;
count++;
}
}
System.out.println("数字和" + sum + ",平均值" + (1. * sum / count));
}
public static String readData() throws IOException {
byte[] res = new byte[10];
int len = 0;
while (true) {
//具体的键盘录入和应用编码无关,这里是按照一个InputSteam进行使用
int kk = System.in.read();
if (kk == '\r' || kk == '\n')
break;
res[len++] = (byte) kk;
}
return new String(res, 0, len);
}
}
用来读写外设字符的,它们都是字节流。如果编程人员愿意,可以用基于字符的流来包装它们
System.out.println("提示信息:");
try {// 从键盘上读取一个字节的数据并返回读取的 int 类型内容 0-255 ,如果输入中文则会出现乱码,因为一个中文是 2 个字节构成// 如果用户不输入任何内容,则当前程序会在这里阻塞等待,直到用户输入为止 ---BIOint kk = System . in . read (); // 这个方法上有个 IOException 异常,属于受检型异常,必须进行处理,处理方法有 throws 或者 try/catchSystem . out . println (( char ) kk ); // 将读取内容转换为 char 类型进行显示} catch ( Exception e ) {e . printStackTrace ();}
使用字节数组读取一组内容
System . out . println ( " 提示信息: " );byte [] buffer = new byte [ 8192 ]; // 注意一般设置缓存默认值都是 8192--8Ktry {// 从键盘读取内容放入到 buffer 字节数组中,并返回读取的字节数 . 如果用户不输入数据则一直阻塞等待int len = System . in . read ( buffer );// 如果输入的是中文信息,则会多两个字节长 [ 和操作系统平台相关 ], 不管中文信息中字符个数 ,一个中文为 2 个字节if ( len > 0 ){System . out . println ( " 读取的字节数为: " + len );String str = new String ( buffer ); // 将数组内容转换为 String 类型数据System . out . println ( str );}} catch ( Exception e ) {e . printStackTrace ();}
- FileInputStream、FileOutputStream 顺序读取文件
- PipedInputStream、PipedOutputStream 管道
- ByteArrayInputStream、ByteArrayOutputStream 内存读写
- FilterInputStream、FilterOutputStream 过滤流(有多线程同步)
- DataInputStream、DataOutputStream 对数据类型读写,有多线程同步
- BufferedInputStream、BufferedOutputStream 缓冲类型读写
- FileInputStream是InputStream的子类,FileInputStream属于节点流,用于按字节读取文件内容
- FileOutputStream是OutputStream的子类,FileOutputStream属于节点流,用于按字节输出数据到文件中
//FileInputStream中read方法的定义
/**从指定的输入流中按字节读取数据,如果读到流的末尾则返回 -1, 否则返回读取到的数据。如果文件不存在则异常 FileNotFoundException 【 IOException 的子类】*/public int read () throws IOException {return read0 ();}
//FileOutputStream中write方法的定义
// 属性 , 用于表示是否进行文件的追加操作而不是覆盖操作private final boolean append ;// 构造器方法的定义,其中 name 是文件名称,默认采用覆盖操作public FileOutputStream ( String name ) throws FileNotFoundException {this ( name != null ? new File ( name ) : null , false );}// 按照字节执行写出 int 数据,自动会去除多余的字节。如果文件不存在则自动创建新文件,如果文件已经存在则按照 append 的值决定采用的是追加操作还是覆盖操作public void write ( int b ) throws IOException {write ( b , append );}private native void write ( int b , boolean append ) throws IOException ; //由 VM 采用对等类的方式提供实现
public class Test1 {
public static void main ( String [] args ) throws IOException {try ( InputStream is = new FileInputStream ( "c:/ 面向对象文档 .txt" );OutputStream os = new FileOutputStream ( "test.txt" );) {int kk ;while (( kk = is . read ()) != - 1 ) {os . write ( kk );}}}}
2、读取A.java文件并在控制台上显示
File ff = new File("T1.java");
if ( ff . exists ()) { // 如果文件存在则进行拷贝操作,否则提示文件不存在InputStream is = new FileInputStream ( ff );OutputStream os = new FileOutputStream ( "t1.bak" );while ( true ) {int kk = is . read (); // 返回值应该是 0-255 ,如果返回 -1 表示流已经结束if ( kk < 0 ) break ;os . write ( kk );}is . close ();os . close ();} elseSystem . out . println ( "T1.java 文件不存在 " );
InputStream基本输入类
InputStream类是基本的输入类。它定义了所有输入流所需的方法。
- public abstract int read() throws IOException读取一个字节并以整数的形式返回,0-255。如果返回-1已到输入流的末尾。
- public int read(byte b[]) throws IOException读取一系列字节并存储到一个数组,返回实际读取的字节数。如果已经读到输入流的末尾则返回-1
- public void close() throws IOException 关闭输入流并释放资源
- public int read(byte b[],int offset,int length) throws IOException功能为从输入流中读数据。这
方法有几种重载形式,可以读一个字节或一组字节。当遇到文件尾时,返回 -1 。最后一种形式中的offset是指把结果放在 b[] 中从第 offset 个字节开始的空间, length 为长度
-
public long skip (long n) throws IOEnception 从输入流跳过几个字节。返回值为实际跳过的字节 数
OutputStream基本输出类
- public abstract void write(int b)向输入流写入一个字节数据,该字节为参数的低8位。
- public void write(byte b[],int offset,int length)将一个字节类型的数组中的从指定位置offset开始 的length个字节写入到输出流
- public void close( ) 关闭输出流,释放资源
- public void write(byte b[])将一个字节类型的数组中的数据写入到输出流
- public void flush() 清除缓冲区,将缓冲区内尚未写出的数据全部输出
需求:
使用字节流将一个文件进行拷贝
public abstract class InputStream implements Closeable
public abstract class OutputStream implements Closeable, Flushable
所以输入流、输出流都支持自动关闭
小结
try ( 构建 IO 对象 ){ 使用 IO 对象执行操作 }, 如果需要进行异常处理才添加 catch 结构File f = new File ( "c:/ 面向对象文档 .txt" );if ( f . exists ())try ( InputStream is = new FileInputStream ( f );OutputStream os = new FileOutputStream ( "c:/test.abc" );) {byte [] buffer = new byte [ 8192 ];int len = 0 ;while (( len = is . read ( buffer )) > 0 ) {os . write ( buffer , 0 , len );}}
字符流
Reader抽象类的定义
public abstract class Reader implements Readable , Closeable {//BIO ,读取一个有效的字符,返回值为 0 到 65535 的整数,如果到达流的末尾则返回 -1public int read () throws IOException//BIO, 读取字符存储到 char 数组中,返回读取的字符个数,流结束则返回 -1public int read ( char cbuf []) throws IOException// 关闭流,同时释放资源abstract public void close () throws IOException ;
Writer抽象类的定义
public abstract class Writer implements Appendable , Closeable , Flushable {// 写出一个字符到字符流,要写的字符包含在给定整数值的 16 个低位; 16 个高位被忽略。public void write ( int c ) throws IOException// 将字符数组中的指定部分内容压入到字符流,从 off 开始共 len 个字符abstract public void write ( char cbuf [], int off , int len ) throwsIOException ;/ 关闭流,同时释放资源abstract public void close () throws IOException ;
相关的子类
- InputStreamReader、OutputStreamWriter桥接流,用于自动实现字节流和字符流的转换
- FileReader、FileWriter文件流,用于实现针对文本文件的读写操作
- CharArrayReader、CharArrayWriter内存流,用于实现针对char数组的读写操作
- PipedReader、PipedWriter管道流,用于线程之间的通讯
- FilterReader、FilterWriter过滤流的父类
- BufferedReader、BufferedWriter缓存流,用于在流中添加缓冲区
- StringReader、StringWriter内存流,用于实现针对字符串的读写操作
字符流Reader
- int read()读取一个字符并以整数的形式返回0-65535,如果返回-1则已到输入流末尾
- int read(char[] cbuf)读取一系列字符并存储到一个数组中,返回实际读取的字符数,如果读到输入流末尾则返回-1
- void close()关闭输入流并释放内存资源
- int read(char[] cbuf, int off, int len) 读取len个字符并存储到一个数组中,从off位置开始,返回实际读取的字符数,如果读取到输入流末尾则返回-1
- long skip(long n)跳过n个字符不读,返回实际跳过的字节数
字符流Writer
- void write(int c) 将字符(int数组的低8位)压入到字符流中
- void write(char[] cbuf, int off, int len)将字符数组中的指定部分内容压入到字符流中,从off开始共len个字符
- void write(String str) 将字符串中的内容压入到字符流中
- void close() 关闭流并释放所占用的资源
- void write(String str, int off, int len) 将字符串中的指定部分内容压入到字符流中,从下标off开始共len个字符
- void flush()刷新缓冲区,将缓冲区中的数据全部送出到目标地,然后清空缓冲区
- void write(char[] cbuf) 将字符数组中的所有数据压入到字符流中
小结
- 在学些BIO时记忆父类的方法,区分子类的实现不同
- InputStream中的方法 read(byte[]):int; Reader中方法read(char[]):int 如果到达流末尾则-1
- OutputStream中的方法 write(byte[],0,len):void;Writer中的方法 write(char[],0,len)/write(String)
- 一般在使用中,如果读取数据使用字节流,则写出数据采用的也是字节流;不建议混用,除非引入桥接流
- 文件流
- FileInputStream("file-name") FileInputStream(File) FileNotFoundException
- FileReader("file-name") FileReader(File) FileNotFoundException
- FileOutputStream("file-name") FileOutputStream("file-name",true) 默认文件覆盖,如果参数true表示追加
- FileWriter("file-name") FileWriter("file-name",true)
- 一般不使用单字节或者单字符的操作方法,使用数组
习题 :
1,字符串进行加工,得到想要的格式,String.format()函数相当于将括号内的数据,按照自己的想要的格式拼接成一个字符串
package com.yan4;
import java.io.IOException;
import java.io.OutputStream;
/*
* 字符串进行加工,得到想要的格式,String.format()函数相当于将括号内的数据,
* 按照自己的想要的格式拼接成一个字符串
*
* %s表示字符串 %d表示整数
*/
public class Test2 {
public static void main(String[] args) throws IOException {
int sum = 100;
int count = 3;
System.out.println("数字和" + sum + ",平均值" + (1. * sum / count));
String ss = "我叫%s,数字和%d,平均值%f"; // 字符串格式模板
String ss2 = String.format(ss, "俗气真", sum, (1. * sum / count));
System.out.println(ss2);
byte[] arr = ss2.getBytes();
OutputStream os = System.out;
os.write(arr);
}
}
2,FileInputStream是InputStream的子类,FileInputStream属于节点流,用于按字节读取文件内容 FileOutputStream是OutputStream的子类,FileOutputStream属于节点流用于按字节输出数据到文件中
package com.yan5;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/*
* - FileInputStream是InputStream的子类,FileInputStream属于节点流,
* 用于按字节读取文件内容
*
* - FileOutputStream是OutputStream的子类,FileOutputStream属于节点流
* ,用于按字节输出数据到文件中
*/
public class Test1 {
public static void main(String[] args) throws Exception{
/*
* 从指定的输入流中按字节读取数据,如果读到流的末尾则返回-1,否则返回读取到的数据。如果文件不存在则异常FileNotFoundException【
* IOException的子类】
*
* public int read() throws
* IOException { return read0(); }
*/
OutputStream os=new FileOutputStream("d:/data.txt",true);
for(int i=0;i<10;i++) {
os.write(i);
}
os.close();
}
}
3,编写一个程序实现如下功能,从当前目录下的文件fin.txt中读取80个字节(实际读到的字节数可能比80少)并将读来的字节写入当前目录下的文件fout.txt
package com.yan6;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
/*
* 编写一个程序实现如下功能,从当前目录下的文件fin.txt中读取80个字节
* (实际读到的字节数可能比80少)并将读来的字节写入当前目录下的文件
* fout.txt
*/
public class Test5 {
public static void main(String[] args) throws Exception {
try (InputStream is = new FileInputStream("data/package-info.java");
OutputStream os = new FileOutputStream("data/fout.txt")) {
for(int i=0;i<11;i++) {
int kk=is.read();
if(kk==-1)
break;
os.write(kk);
}
}
System.out.println("copy end...");
}
}
4,编写一个程序实现如下功能,文件fin.txt是无行结构(无换行符)的包含中文字符的文本文件,从fin中读取字符,写入文件fou.txt中,每40个字符一行(最后一行可能少于40个字)
package com.yan7;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.io.Writer;
/*
* 编写一个程序实现如下功能,文件fin.txt是无行结构(无换行符)的包含中文字符的文本文件,从fin中读取字符,写入文件fou.txt中,每40个字符一行(最后一行可能少于40个字)
*/
public class Test1 {
public static void main(String[] args) throws Exception {
try (Reader r = new FileReader("data/input.txt"); Writer w = new FileWriter("data/fout40.txt");) {
int cc = 0;// 计数器
while (true) {
int kk = r.read();
if (kk == -1)
break;
cc++;
w.write(kk);
if (cc % 10 == 0)
w.write('\n');
}
}
}
}
5, 统计一个文件calcCharNum.txt中字母'A'和'a'出现的总次数
package com.yan7;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
/*
* 统计一个文件calcCharNum.txt中字母'A'和'a'出现的总次数
*/
public class Test2 {
public static void main(String[] args) throws IOException {
try (Reader r = new FileReader("data/calcCharNum.txt")) {
int cc=0;
while(true) {
int kk=r.read();
if(kk==-1)
break;
if(kk=='A' || kk=='a')
cc++;
}
System.out.println(cc);
}
}
}
6, 统计一个文件calcCharNum.txt中各个字符出现次数:A(8),B(16),C(10)...,a(12),b(10),c(3)....,括号内代表字符出现次数;
package com.yan7;
import java.io.FileReader;
import java.io.Reader;
/*
* 统计一个文件calcCharNum.txt中各个字符出现次数:A(8),B(16),C(10)...,a(12),b(10),c(3)....,括号内代表字符出现次数;
*/
public class Test3 {
public static void main(String[] args) throws Exception {
ArrayList al = new ArrayList();
try (Reader r = new FileReader("data/package-info.java");) {
for (;;) {
int kk = r.read();
if (kk == -1)
break;
al.add((char) kk);
}
}
al.show();
}
}
class CharNum {
private char ch;
private int num;
public CharNum(char ch) {
this.ch = ch;
this.num = 1;
}
public void incr() {
this.num++;
}
@Override
public String toString() {
return ch + "(" + num + ")";
}
public char getCh() {
return ch;
}
}
class ArrayList {
private CharNum[] array;
private int count = 0;
public ArrayList() {
this(10);
}
public ArrayList(int length) {
if (length < 0)
throw new IllegalArgumentException("数组长度异常");
array = new CharNum[length];
}
public void add(char ch) {
int res = this.exists(ch);
if (res >= 0) {
array[res].incr();
} else {
array[count++] = new CharNum(ch);
if (count == array.length) {
incrCapacity();
}
}
}
public void show() {
for (int i = 0; i < count; i++)
System.out.print(array[i] + ",");
}
private void incrCapacity() {
CharNum[] carr = new CharNum[array.length * 3 / 2];
for (int i = 0; i < array.length; i++)
carr[i] = array[i];
this.array = carr;
}
private int exists(char ch) {
int res = -1;
for (int i = 0; i < count; i++) {
CharNum cn = array[i];
if (cn.getCh() == ch) {
res = i;
break;
}
}
return res;
}
}
7,编写一个程序,把指定目录下的所有的带.java文件都拷贝到另一个目录中拷贝成功后,把后缀名是.java的改成.txt
package com.yan7;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
/*
* 练习:编写一个程序,把指定目录下的所有的带.java文件都拷贝到另一个目录中
* ,拷贝成功后,把后缀名是.java的改成.txt
*
*
* 例如src下多个文件位于src的子目录中,如果文件名称重复,则需要改名称,在名称后面添加(n)
*/
public class Test4 {
private static String tardic = "d:/bbb";
public static void main(String[] args) {
search(new File("src"));
}
private static void copy(File source) {
System.out.println("拷贝文件" + source.getAbsolutePath());
File f1 = new File(tardic);
if (!f1.exists())
f1.mkdirs();
int cc = 0;
String fileName = source.getName();
String sourceName = fileName;
File f2 = null;
while (true) {
f2 = new File(f1, fileName);
if (!f2.exists()) {
break;
} else {
fileName = sourceName.substring(0, sourceName.lastIndexOf("."));
fileName = fileName + "(" + (cc++) + ").java";
}
}
try (Reader r = new FileReader(source); Writer w = new FileWriter(f2);) {
char[] buffer=new char[8192];
int len=0;
while((len=r.read(buffer))>0) {
w.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void search(File file) {
if (file.exists()) {
if (file.isFile()) {
String fileName = file.getName();// 获取文件的简称
if (fileName != null && fileName.endsWith(".java")) {
copy(file);
}
} else if (file.isDirectory()) {
File[] fs = file.listFiles();
if (fs != null && fs.length > 0) {
for (File tmp : fs)
search(tmp);
}
}
}
}
}
8,编写一个程序,其功能是将多个文本文件的内容合并到一个文本文件中
package com.yan7;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.io.Writer;
//编写一个程序,其功能是将多个文本文件的内容合并到一个文本文件中
public class Test5 {
public static void main(String[] args) throws Exception {
try (Writer w = new FileWriter("data/all.txt");) {
File file = new File("src/com/yan7");
File[] fs = file.listFiles((File dir, String name) -> {
return name != null && name.endsWith(".java");
});
for (File tmp : fs) {
try (Reader r = new FileReader(tmp);) {
char[] buffer = new char[8192];
int len = 0;
while ((len = r.read(buffer)) > 0)
w.write(buffer, 0, len);
}
}
}
}
}
9,找到一个大于100k的文件,按照100k为单位,拆分成多个子文件,并且以编号作为文件名结束。比如文件eclipse.exe
package com.yan7;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
/*
* 找到一个大于100k的文件,按照100k为单位,拆分成多个子文件,并且以编号作为文件名结束。比如文件eclipse.exe,大小是309k。拆分之后,成为eclipse.exe-0、eclipse.exe-1、eclipse.exe-2、eclipse.exe-3
*/
public class Test6 {
public static void main(String[] args) throws Exception {
try (InputStream is = new FileInputStream("D:\\software\\eclipse2022/eclipse.exe");) {
byte[] buffer = new byte[100 * 1024];
int lens = 0;
int cc = 0;
OutputStream os = new FileOutputStream("data/eclipse.exe-" + cc++);
while (true) {
int len = is.read(buffer);
if (len == -1)
break;
for (int i = 0; i < len; i++) {
os.write(buffer[i]);
lens++;
if (lens >= 100 * 1024) {
lens = 0;
os.close();
os = new FileOutputStream("data/eclipse.exe-" + cc++);
}
}
}
}
}
}