IO流
输入流:把数据从其他设备上读取到内存中的流
输出流:把数据从内存中写出到其他设备上的流
根据数据内存的不同,可分为字节流和字符流
一切文件都是字节
IO字节流
注意:这里的输入输出都是对内存来说的,输入就是把内容从硬盘中写到内存中,输出就是把内容从内存中写到硬盘中。
OutputStream(字节输出流)
OutputStream是所有表示字节输出流的超类,其中定义了一些共有的方法
void close()
关闭此输出流并释放与此流有关的所有系统资源。
void flush()
刷新此输出流并强制写出所有缓冲的输出字节。
void write(byte[] b)
将 b.length 个字节从指定的 byte 数组写入此输出流。
void write(byte[] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
abstract void write(int b)
//将指定的字节写入此输出流。
OutputStream是接口,需要实现类才能使用。下面简单介绍几种实现类。
FileOutputStream
文件字节输出流,作用是把内存中的数据写到硬盘的文件中
构造方法:
FileOutputStream(File file) //创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(String name) //创建一个向具有指定名称的文件中写入数据的输出文件流。
FileOutputStream(File file, boolean append)//创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(String name, boolean append)//创建一个向具有指定 name 的文件中写入数据的输出文件流。
/*boolean append :当append是true时,创建文件不会覆盖源文件,会续写
当append是false时,创建文件会覆盖源文件,不会续写
*/
public static void main(String[] args) throws IOException {
File file=new File("E:\\百度网盘\\1.txt",true);
FileOutputStream f=new FileOutputStream(file);
f.write("2093497021".getBytes());
f.write(123456);//当数不在0~127之间时会查询系统默认编码
f.write("qq.com".getBytes());
f.write("\r\n".getBytes());//\r\n是换行符号
f.write("wodeshijie".getBytes());//可以通过字符串的方法写入数据
f.close();
}
需要注意的是,路径不对会抛出异常,使用时也可能也会产生异常,所以需要处理。
写入数据的原理(内存–>硬盘)
java程序–>JVM(java虚拟机)–>OS(操作系统)–>OS调用写数据的方法–>把数据写入文件中
写入的数据都是二进制的值,当打开文件时,会查询ASCII表(0~127)或查询系统默认码表进行编译。
InputStream(字节输入流)
是所有字节输出流的超类,定义了一些共用的方法:
void close()
关闭此输入流并释放与该流关联的所有系统资源
abstract int read()
从输入流中读取数据的下一个字节。
int read(byte[] b)
从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
FileInputStream
是IntputStream的实现类,可以读取数据(硬盘–>内存)。构造方法:
FileInputStream(File file)
FileInputStream(String name)
FileInputStream在使用时读取文件中的字节,每使用一次read方法,指针就会朝后移动一下。注意read方法的返回值是读取字节的个数。可以一个字节一个字节的读取,也可以多个字节一起读取,使用完后还需要close()释放资源。
public static void main(String[] args) throws IOException {
File file=new File("E:\\files\\IJ\\xusir\\src\\EverydayPractic\\xu.txt");
File file1=new File("E:\\百度网盘\\1.txt");
FileInputStream fis=new FileInputStream(file);//输出流
FileOutputStream fos=new FileOutputStream(file1,true);//输出流
byte[] b=new byte[1024];//字节一下读取1024字节=1kb,或1024的整数倍
int len=0;
while ((len=fis.read(b))!=-1){
fos.write(new String(b,0,len).getBytes());
fos.write("\r\n".getBytes());//换行
}
fis.close();
fos.close();
}
附:复制特定格式文件的代码实现:
//main方法
public static void main(String[] args) throws IOException {
//需要复制的文件地址
File file1 = new File("E:\\files\\IJ\\xusir\\src");
getFiles(file1);
}
//复制的方法
public static void getFiles(File file) throws IOException {
byte[] b = new byte[1024];
int len = 0;
//过滤器(lambda表达式实现)
File[] files = file.listFiles((File file2, String name) ->
//需要复制的文件的类型
file2.isDirectory() || name.endsWith(".java"));
for (File f : files) {
if (f.isDirectory())
getFiles(f);
else {
FileInputStream fis = new FileInputStream(f);
//复制的地址
FileOutputStream fos = new FileOutputStream(new File("D:\\wode\\", f.getName()), true);
while ((len = fis.read(b)) != -1) {
fos.write(b, 0, len);
}
fis.close();
fos.close();
}
}
}
IO字符流
用字节输入流读取数据时,如果需要读取的对象是中文或其他一个字节不能表示的对象时,就不能一下读取到其所表示的内容,当需要表示特定位置的内容时,用字节流也显得力不从心。因此有了IO字符流。
Reader字符输入流
Reader是所有字符输入流的超类,定义了一些共有的方法。主要有三个:
void close()
//关闭该流并释放与之关联的所有资源。
int read()
//读取单个字符。
int read(char[] cbuf)
// 将字符读入数组。
FileReader
读取文件中的字符,与字节输入流的使用方法是一模一样的,区别仅仅是一个读取的是字节,一个读取的是字符。
Writer字符输出流
Writer是所有字符输出流的超类。
void close()
关闭此流,但要先刷新它。
void flush()
刷新该流的缓存。
void write(int c)
//写入单个字符
void write(String str)
//写入字符串
void write(char[] b)
写入字符数组
abstract void write(char[] b, int off, int len)
写入指定长度的字符数组,off为开始索引,len为写入长度。
void write(char[] b, int off, int len)
写入字符串的某一部分,off为开始索引,len为写入长度。
FileWriter
创建方法与FileInputStream的创建方法一模一样
注意:FileWriter会把数据写到缓存区,因此在没写flush或close方法时,文件处于没有接受数据的情况。
fiush和close的区别:
flush:刷新缓存区,流对象还可以使用。
close:先刷新缓存区,再释放资源,流对象不能再使用了。
Properties
Properties继承Hashtable,来表示一个持久的属性集。它使用键值对结构存储数据,每个键及其对应值都是一个字符串。 是唯一与IO流结合的集合。
方法:
void load(InputStream inStream)
//把硬盘中的文件(键值对)读到内存中使用
void load(Reader reader)
void store(OutputStream out, String comments)
//把集合中的临时数据持久化写入到硬盘中存储
void store(Writer writer, String comments)
说明:comments是注释一般写“ ”就行了。不能写中文,会编译错误的。
操作字符串的特有方法:
String getProperty(String key)
//获取特定键的值
Object setProperty(String key, String value)
//调用 Hashtable 的方法 put,存储数据
Set stringPropertyNames()
//返回此属性列表中的键集,其中该键及其对应值是字符串。
public static void main(String[] args)throws IOException {
Properties prop1 =new Properties();
FileWriter fw=new FileWriter("E:\\files\\IJ\\xusir\\src\\EverydayPractic\\a.txt");
prop1.setProperty("A","18");
prop1.setProperty("B","18");
prop1.setProperty("C","17");
prop1.setProperty("D","19");
prop1.store(fw,"name plus age");
fw.close();
FileReader fr=new FileReader("E:\\files\\IJ\\xusir\\src\\EverydayPractic\\a.txt");
Properties prop2=new Properties();
prop2.load(fr);
Set<String> str = prop2.stringPropertyNames();
for (String key : str) {
System.out.println(key+"="+prop2.getProperty(key));
}
fr.close();
}
读取文件内容时,#当作注释,不会读取。
缓存流
创建一个缓存区,先把数据传到缓存区,再对数据进行操作,与使用流时创建一个数组的作用是一样的。可分为字节缓存输入流(BufferedInputStream)、字节缓存输出流(BufferedOutputStream)、字符缓存输入流(BufferedRead)、字符缓存输出流(BufferedWriter)四种。这四种缓存流分别继承了它们对应的流。如BufferedOutputStream继承OutputStream,所以缓存流可以使用父类的方法。缓存流要比一般的IO流要快许多。
创建方法:
字节缓存输入流
BufferedInputStream(InputStream in)创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
BufferedInputStream(InputStream in, int size) 创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用
字节缓存输出流 、字符缓存输入流、字符缓存输出流的创建方法与字节缓存输入流的一样。这里就不再多说,使用方法与IO流的大同小异。
注意
1、BufferedRead有一个特有的方法String readLine()
,可以一下读取一个行,需要注意的是,该方法读取到换行标记时会停止,所以读取的数据中没有换行标记,如果再输入到文件中时不会换行。当没有文件可读时会返回null,而不是-1.
2、BufferedWriter中也有一个特有的方法void newLine()
,换行。这个方法会自动识别系统并输入对应换行符。