- 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成。
- 程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件。
字节流与字符流
在java.io包中操作文件内容的主要有两大类:字节流、字符流,两类都分为输入和输出操作。在字节流中输出数据主要是使用OutputStream完成,输入使的是InputStream,在字符流中输出主要是使用Writer类完成,输入流主要使用Reader类完成。(这四个都是抽象类)
字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好!如果是音频文件、图片、歌曲,就用字节流好点,如果是关系到中文(文本)的,用字符流好点
1.字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串; 2. 字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以
filewriter写入字符
import java.io.FileWriter;
import java.io.IOException;
public class filewriterdemo {
public static final String PATH = "E:\\JavaBook\\MyprojectTouTiao\\MyAlgorithms\\filewriter\\" ;
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static void main(String []args) throws IOException {
FileWriter fw = new FileWriter(PATH+"demo.txt");
//第一步创建对象,必须明确该文件(用于存储数据的目的地。
// 如果文件不存在,自动建立。若存在,则被覆盖
fw.write("absdfskjdf");
// 调用writer对象中的writer(String)方法,写入数据。
// 其实数据是写入临时缓冲区
fw.write(LINE_SEPARATOR);
//若要实现写入时换行。
fw.write("sagsfg\r\nsfsagsa");
//或者调用系统的换行属性
fw.write("abcde"+LINE_SEPARATOR+"hahahah");
fw.flush();
// 刷新以后,将数据写进目的地;
fw.close();
// 关闭流,关闭资源。关闭之后不能写数据。
}
}
使用数组读取文件数据:类似于缓冲区
import java.io.FileReader;
import java.io.IOException;
public class FileWriterdemo2 {
public static final String PATH = "E:\\JavaBook\\MyprojectTouTiao\\MyAlgorithms\\filewriter\\" ;
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static void main(String[]args)
{
FileReader fr = null;
try {
fr = new FileReader(PATH+"demo.txt");
// 使用read(char[])读取文本文件数据
char[] buf = new char[1024];
int len = 0;
while ((len = fr.read(buf))!=-1)
{
System.out.println(new String(buf,0,len));
}
} catch (IOException e) {
e.printStackTrace();
}
finally {
if(fr!=null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
使用字符流缓冲区提高文件读取和写入的效率:
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferWriterDemo {
public static final String PATH = "E:\\JavaBook\\MyprojectTouTiao\\MyAlgorithms\\filewriter\\" ;
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static void main(String [] args) throws IOException
{
FileWriter fw = new FileWriter(PATH+"buf.txt");
//创建一个字符写入流的缓冲区对象,并和指定要被缓冲的流对象相关联。
BufferedWriter bufw = new BufferedWriter(fw);
// 使用缓冲区的写入方法将数据先写入到缓冲区中。
bufw.write("abcdef\r\ngsdagdfg");
// 使用缓冲区的刷新方法将数据刷新到目的地。
bufw.flush();
//缓冲区读取数据
FileReader fr = new FileReader(PATH+"buf.txt");
BufferedReader bufr = new BufferedReader(fr);
String line = null;
while ((line=bufr.readLine())!=null)
System.out.println(line);
//关闭缓冲区,相当于关闭了流对象
bufw.close();
}
}
#结果:abcdef
#gsdagdfg
实现从磁盘读取数据到内存,再从内存中读到缓冲区过程:
import java.io.FileReader;
import java.io.IOException;
public class MybufferReader {
private FileReader fr;
//定义一个缓冲区。
private char[] buf = new char[1024];
//定义一个指针用于操作这个数组中的元素,当操作到最后一个元素后,指针归零。
private int pos = 0;
//定义一个计数器用于记录缓冲区中的数据个数,当该数据减到0时,就从源中继续获取数据到缓冲区中。
private int count = 0;
MybufferReader(FileReader r)
{
this.fr = r;
}
public int myread() throws IOException
{
if(count==0)
{
count = fr.read(buf);
pos=0;
}
if(count<0)
return -1;
char ch = buf[pos++];
count--;
return ch;
}
public String myreaderLine() throws IOException
{
StringBuilder sb = new StringBuilder();
int ch = 0;
while ((ch=myread())!=-1)
{
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
// 将缓冲区中读取的字符,存储到缓冲行数据的缓冲行中
sb.append((char)ch);
}
if(sb.length()!=0)
return sb.toString(); //对于最后一个没有回车的行,也要返回才对。
return null;
}
public void myclose() throws IOException
{
fr.close();
}
}
测试代码:
import java.io.*;
public class copytextBUfferTest {
public static final String PATH = "E:\\JavaBook\\MyprojectTouTiao\\MyAlgorithms\\filewriter\\" ;
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
/**
* 缓冲的原理:
* 就是从源中获取一批数据装进缓冲区中,
* 在从缓冲区中不断的取出一个一个数据。
*
* 在此次取完后,再从源中继续读取一批数据经缓冲区。
* 当源中数据取光时, 用-1作为结束的标志。
*/
public static void main(String [] args) throws IOException {
//FileWriter fw = new FileWriter(PATH + "buf_copy.txt");
创建一个字符写入流的缓冲区对象,并和指定要被缓冲的流对象相关联。
//缓冲区读取数据
FileReader fr = new FileReader(PATH + "buf.txt");
//BufferedReader bufr = new BufferedReader(fr);
MybufferReader bufr = new MybufferReader(fr);
String line = null;
while ((line=bufr.myreaderLine())!=null)
{
System.out.println(line);
}
bufr.myclose();
}
}
字节流与字符流的区别
1.字节流和字符流使用是非常相似的,那么除了操作代码的不同之外,还有哪些不同呢?
- 字节流在操作的时候本身是不会用到缓冲区(内存)的,是与文件本身直接操作的,而字符流在操作的时候是使用到缓冲区的
- 字节流在操作文件时,即使不关闭资源(close方法),文件也能输出,但是如果字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲区,并且可以使用flush方法强制进行刷新缓冲区,这时才能在不close的情况下输出内容
2.那开发中究竟用字节流好还是用字符流好呢?
- 在所有的硬盘上保存文件或进行传输的时候都是以字节的方法进行的,包括图片也是按字节完成,而字符是只有在内存中才会形成的,所以使用字节的操作是最多的。
- 如果要java程序实现一个拷贝功能,应该选用字节流进行操作(可能拷贝的是图片),并且采用边读边写的方式(节省内存)
操作字节流:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamDemo {
public static final String PATH = "E:\\JavaBook\\MyprojectTouTiao\\MyAlgorithms\\filewriter\\" ;
public static void main(String []args) throws IOException
{
//demo_write();
demo_read();
}
private static void demo_read() throws IOException {
// 1.创建一个读取流对象,和指定文件关联。
FileInputStream fi = new FileInputStream(PATH+"bytedemo.txt");
byte [] buf = new byte[1024];
int len = 0;
while ((len=fi.read(buf))!=-1)
{
System.out.println(new String(buf, 0, len));
}
//byte [] buf = new byte[fi.available()];
//fi.read(buf);
//System.out.println(new String(buf));
}
private static void demo_write() throws IOException
{
// 1.创建字节输出流对象,用于操作文件。
FileOutputStream fos = new FileOutputStream(PATH+"bytedemo.txt");
// 2.写入数据,直接写入到目的地。
fos.write("absdfsdf".getBytes());
// 不需要刷新。flush()
// 直接关闭流
fos.close();
}
}