1.IO是什么意思? data source是什么意思?
IO:Input Output;
data source:数据源。
2.字节流和字符流有什么区别?输入流和输出流有什么区别?
字符流和字节流是流的一种划分,按照处理流的数据单位进行的划分。两类都分为输入和输出操作。在字节流中输出数据主要是使用OutputStream完成,输入使用的是InputStream,在字符流中输出主要是使用Writer类完成,输入流主要使用Reader类完成。这四个都是抽象类。字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。字节流是最基本的,所有的InputStrem和OutputStream的子类都是字节流,主要用在处理二进制数据,它是按字节来处理的。但实际中很多的数据是文本,又提出了字符流的概念,它是按虚拟机的编码来处理,也就是要进行字符集的转化,这两个之间通过 InputStreamReader,OutputStreamWriter(转换流)来关联,实际上是通过byte[]和String来关联的。
流就像管道一样,在程序和文件之间,输入输出的方向是针对程序而言,向程序中读入东西,就是输入流,从程序中向外读东西,就是输出流。输入流是得到数据,输出流是输出数据。
3.节点流和处理流有什么区别?
节点流和处理流是流的另一种划分,按照功能不同进行的划分。节点流,可以从或向一个特定的地方(节点)读写数据。处理流是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。
4.word文档能使用字符流操作吗?为什么?
不能。因为word文档不是纯文本文件,除了文字还包含很多格式信息。不能用字符流操作。可以用字节流操作。
305.【上机】完成老师课堂上读入文件数据的代码:
static void testReader(){
File f = new File("d:/a.txt");
FileInputStream fis = null;
try {
fis = new FileInputStream(f);
int m = 0;
while((m=fis.read())!=-1){
char c = (char) m;
System.out.print(c);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(fis!=null){
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
5.解释下面代码的含义:
通过上例得知fis是字节输入流对象,fis.read()是每次从指定文件读取一个字节,返回值是这个字节所代表的int类型的整数。如果读到文件结尾(没有内容可读了),那么返回-1。
下面的代码是依次读取文件,每次一个字节,循环读取;每次读完后将返回的整数值(m)转成char类型的数据(强转)(从而知道每次读取的是什么字符),输出这个字符。直到读完为止。
while((m=fis.read())!=-1){
char c = (char) m;
System.out.print(c);
}
6.流对象使用完后,一般要调用close方法关闭,释放资源。 这种做法对吗?
对。
7.【上机】完成老师写文件的操作:
static void testWrite(){
FileOutputStream fos = null;
String str = "sffsdfsdfsdfsdfsdfsdfsdf";
try {
fos = new FileOutputStream("d:/b.txt");
/*for(int i=0;i<str.length();i++){
fos.write(str.charAt(i));
}*/
fos.write(str.getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(fos!=null){
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
8.InputStream和OutputStream基本特点是?
二者都是【字节】输入输出流的抽象父类。以字节为单位处理数据,每次读取/写入一个字节。适合处理二进制文件,如音频、视频、图片等。实现类有FileInputStream和FileOutputStream等。
9.Reader和Writer的基本特点是?
二者都是【字符】输入输出流的抽象父类。以字符为单位处理数据,每次读取/写入一个字符。适合处理文本文件。实现类有FileReader和FileWriter等。
10.FileInputStream和FileOutputStream的基本作用是?
二者都是【字节】输入输出流的实现类,其抽象父类是InputStream和OutputStream。以字节为单位处理数据,每次向/从指定文件读取/写入一个字节。适合处理二进制文件,如音频、视频、图片等。
11.FileReader和FileWriter的作用是?
二者都是【字符】输入输出流的实现类,其抽象父类是Reader和Writer。以字符为单位处理数据,每次向/从指定文件读取/写入一个字符。适合处理文本文件。
12.【上机】完成文件的copy代码
思路:先把源文件读到程序里,在从程序写到目标文件。
代码示例:
//1.创建数据源文件;
File file=new File("e:\picture1.jpg");
//2.搭建输入流管道;
InputStream is=new FileInputStream(file);
//3.创建目的地文件;
File file1=new File("e:\picture2.jpg");
//4.搭建输出流管道;
OutputStream os=new FileOutputStream(file1);
int b=0;
//每次从源文件读出一个字节(b=is.read()),就向目标文件写入一个字节
//(os.write(b));
while((b=is.read())!=-1){
os.write(b);
}
//读写全部完成后关闭资源;
os.close();
is.close();
}
13.BufferInputStream和BufferedOutputStream的特点是?
BufferInputStream和BufferedOutputStream分别是【缓冲】字节输入输出流,还有【缓冲】字符输入输出流(BufferReader和BufferedWriter)。
缓冲流是处理流,它不直接连接数据源/目的地,而是以一个节点流为参数,在节点流的基础上,提供一些简单操作。
先说不带缓冲的流的工作原理吧:它读取到一个字节/字符,就向用户指定的路径写出去,读一个写一个,所以就慢了。带缓冲的流的工作原理:读取到一个字节/字符,先不输出,等凑足了缓冲的最大容量后一次性写出去,从而提高了工作效率
优点:减少对硬盘的读取次数,降低对硬盘的损耗。
14.【上机】使用BufferedReader和BufferedWriter实现文本文件的拷贝。
//第一部分:准备从文件读数据到程序;
Reader reader=new FileReader(new File("e:\a.txt"));//创建读取对象reader;
BufferedReader br=new BufferedReader(reader); //创建缓冲流包装reader;
//第二部分:准备从程序写到文件;
Writer writer=new FileWriter(new File("e:\a3.txt"));//创建写入对象writer;
BufferedWriter bw=new BufferedWriter(writer);//创建缓冲流包装writer;
String str=null;
//用循环边读(str=br.readLine())边写(bw.write(str));
while((str=br.readLine())!=null){
bw.write(str);
bw.newLine();
}
bw.flush();//清空缓冲区;
//copy完成后关闭资源;
bw.close();
br.close();
}
15.InputStreamReader和OutputStreamWriter的作用是?
二者都是转换流,从字节流转换为字符流,是包装流,以一个节点流为参数;提供一些方便读写【字符】的方法。
代码示例(InputStreamReader):
publicstaticvoid main(String[] args) throws IOException {
//1.节点流;
InputStream is=new FileInputStream(new File("e:\a1.txt"));
//2.处理流:把字节流转换成了字符流;
InputStreamReader isr=new InputStreamReader(is,"utf-8");
int temp=0;
//用转换流对象isr进行读取操作,以字符(而不是字节)为单位读取文本文件,方便操//作。
while((temp=isr.read())!=-1){
System.out.print((char)temp);
}
isr.close();
}
OutputStreamWriter(略).
16.PrintStream打印流经常用于什么情况? System.out 是不是打印流?
PrintStream:字节打印流,是OutputStream的实现类。提供了多个重载的print,println等方法,可以方便地向文本文件中写入数据。
System.out是字节打印流(PrintStream的对象),它被称作标准的输出流,输出的目的地是标准的输出设备,即显示器。所以,当我们使用System.out.print或System.out.println时会向屏幕(显示器)输出数据。
PrintStream的继承关系:
17.【上机】实现字节数组和任何基本类型和引用类型执行的相互转换。
提示:使用ByteArrayInutStream和ByteArrayOutputStream。
1.字节数组和基本数据类型之间的转换,以boolean类型为例:
(1)输出一个boolean类型的数据:
boolean flag=true;//先定义一个boolean类型的变量;
ByteArrayOutputStream baos=new ByteArrayOutputStream();
DataOutputStream dos=new DataOututStream(baos);
dos.writeBoolean(flag);
byte[] b=baos.toByteArray();
//接下来可以把byte数组构建成一个数据包(DatagramPacket)发送出去;
(2)读取一个boolean类型的数据:
byte[] b=new byte[1024];
//我们已接收到包含一个boolean类型数据的数据包(代码略);数据信息已经包含在byte数组b里,接下来就把boolean类型的数据读出来并保持原类型;
ByteArrayInputStream bais=new ByteArrayInputStream(b);
DataInputStream dis=new DataInputStream(bais);
boolean flag=dis.readBoolean();//这样数据就读出来了并保持着原来的数据类型。
2.字节数组和引用类型之间的转换:
(1)输出一个引用类型信息:
//先建一个类,如User(代码略);
User user=new User();
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(baos);
oos.writeObject(user);
byte[] b=baos.toByteArray();
//接下来可以把byte数组构建成一个数据包(DatagramPacket)发送出去;
(2)读取一个引用类型信息:
byte[] b=new byte[1024];
//我们已接收到包含一个User类型数据的数据包(代码略);
//数据信息已经包含在byte数组b里,接下来就把User类型的数据读出来并保持原类型;
ByteArrayInputStream bais=new ByteArrayInputStream(b);
ObjectInputStream ois=new ObjectInputStream(bais);
User user=(User)ois.readObject();//这样数据就读出来了并保持着原来的数据类型。
18.DataInputStream和DataOutputStream的特点是?
二者都是处理流,要以一个节点流为参数;二者被称为数据流,是用来操作基本数据类型的。用DataInputStream写入一个类型的数据,用DataOutputStream读出数据时可以保持类型不变。如用DataInputStream写入一个int类型的数据,用DataOutputStream读出来的还是一个int数据,即可以直接当作int类型的数据来进行操作,不用做任何转换。
代码示例:
publicclass TestDataInputStream {
publicstaticvoid main(String[] args) throws IOException {
//1.写数据;
OutputStream os=new FileOutputStream(new File("e:\f.data"));//构建节点流;
DataOutputStream dos=new DataOutputStream(os);//用数据流包装节点流;
int n=123456;
String str="尚学堂教育";
dos.writeInt(n);//用数据流写入一个int类型的数值(n是int类型的);
dos.writeUTF(str); //用数据流写入一个String类型的数据;
dos.writeDouble(3.15); //用数据流写入一个double类型的数据;
dos.writeChar('我'); //用数据流写入一个char类型的数据;
dos.writeBoolean(true); //用数据流写入一个布尔类型的数据;
//2.读数据;
InputStream is=new FileInputStream(new File("e:\f.data"));
DataInputStream dis=new DataInputStream(is);
int n1=dis.readInt();//用数据流读出刚才写入的int类型数据,赋给int类型变量;
String str1=dis.readUTF();//用数据流读出String类型的数据;
double d=dis.readDouble();//用数据流读出double类型的数据;
char c=dis.readChar();//用数据流读出char类型的数据;
boolean flag=dis.readBoolean();//用数据流读出布尔类型的数据;
//打印输出用数据流读出来的数据;
System.out.println(n1);
System.out.println(str1);
System.out.println(d);
System.out.println(c);
System.out.println(flag);
//关闭资源;
dis.close();
dos.close();
}
}
结果:
123456
尚学堂教育
3.15
我
true
数据流特点:
(1)写入是什么类型的数据,读出是相应类型的数据;
(2)要先写后读;用DataOutputStream流写,用DataInputStream流读;
(3)读写顺序要一致,否则会报EOF异常;EOF:end of file;
(4)数据流可以跨平台写入和读出,适合网路应用。
19.【上机】使用ObjectInputstream和ObjectOutputStream实现将某个对象存 储到硬盘上,然后再读到程序中。
见课堂实例。
20.中文乱码是怎么造成的?
字符流的读写根据需要设置编码方式,编码方式设置不当会出现中文乱码。
21.unicode字符集是几个字节表示一个字符?为什么需要utf-8?
Unicode字符集中2个字节表示一个字符。
22.序列化和反序列化指的是什么?
(1) 序列化:
将对象以byte流的形式写入到文件中->序列化;
将要被序列化的对象的类要实现Serializable接口:
publicclassUserimplements Serializable {
//略;
}
User实现了这个接口,代表User这个类的对象具有了将对象以byte流的形式写进文件的功能。
(2) 反序列化:
将文件中的数据以byte流的形式读到程序中来,依然是一个对象反序列化。
23.想序列化某个类的对象,该类必须实现sierializable接口吗?
要序化的对象必须实现Serializable接口,以启动序列化的功能。
24.说说sierializable接口的特点。
1. 需要被序列化的对象的类必须实现Serializable接口。
2. 给类加个序列化编号,即给类定义一个标记,如:
public static final long serialVersionUID=1L;
新的修改后的类还可以操作曾经序列化的对象。
3、静态是不能被序列化的,
序列化只能对堆中的对象进行序列化 ,不能对”方法区”中的对象进行序列化。
4、不需要序列化的字段前加 transient,如:
private transient String password;
25.transient的作用是?
不希望序列化的属性,可以添加transient关键字;
密码字段是非常敏感的字段,所在在序列化时,不允许写到文件:
private transient String password;
26.【上机】完成目录的copy代码(结合递归算法)
import java.io.*;
/**
* CopyDocJob定义了实际执行的任务,即
* 从源目录拷贝文件到目标目录
*/
public class CopyDir2 {
public static void main(String[] args) {
try {
copyDirectiory("d:/301sxt","d:/301sxt2");
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 复制单个文件
* @param sourceFile 源文件
* @param targetFile 目标文件
* @throws IOException
*/
private static void copyFile(File sourceFile, File targetFile) throws IOException {
BufferedInputStream inBuff = null;
BufferedOutputStream outBuff = null;
try {
// 新建文件输入流
inBuff = new BufferedInputStream(new FileInputStream(sourceFile));
// 新建文件输出流
outBuff=new BufferedOutputStream(new FileOutputStream(targetFile));
// 缓冲数组
byte[] b = new byte[1024 * 5];
int len;
while ((len = inBuff.read(b)) != -1) {
outBuff.write(b, 0, len);
}
// 刷新此缓冲的输出流
outBuff.flush();
} finally {
// 关闭流
if (inBuff != null)
inBuff.close();
if (outBuff != null)
outBuff.close();
}
}
/**
* 复制目录
* @param sourceDir 源目录
* @param targetDir 目标目录
* @throws IOException
*/
private static void copyDirectiory(String sourceDir, String targetDir) throws IOException {
// 检查源目录
File fSourceDir = new File(sourceDir);
if(!fSourceDir.exists() || !fSourceDir.isDirectory()){
return;
}
//检查目标目录,如不存在则创建
File fTargetDir = new File(targetDir);
if(!fTargetDir.exists()){
fTargetDir.mkdirs();
}
// 遍历源目录下的文件或目录
File[] file = fSourceDir.listFiles();
for (int i = 0; i < file.length; i++) {
if (file[i].isFile()) {
// 源文件
File sourceFile = file[i];
// 目标文件
File targetFile = new File(fTargetDir, file[i].getName());
copyFile(sourceFile, targetFile);
}
//递归复制子目录
if (file[i].isDirectory()) {
// 准备复制的源文件夹
String subSourceDir = sourceDir + File.separator + file[i].getName();
// 准备复制的目标文件夹
String subTargetDir = targetDir + File.separator + file[i].getName();
// 复制子目录
copyDirectiory(subSourceDir, subTargetDir);
}
}
}
}
27.【上机】假设从入学开始所有书写的Java代码都在d:/sxtjava文件夹下,包括多
级子文件夹。使用IO流获取从入学开始,到目前为止已经写了多少行Java代码。
提示:获取d:/sxtjava文件夹及其子文件夹下的所有.java文件,使用readLine()读取其中每一行,每读取一行,行数加1。
public class TestCountDir {
private int count;
/**
* 统计一个java文件的行数
*/
private void countLine(File sourceFile) throws IOException {
BufferedReader br = null;
try {
// 新建文件输入流
br = new BufferedReader(new FileReader(sourceFile));
while(br.readLine()!=null){
count++;
//System.out.println(count);
}
} finally {
br.close();
}
}
/**
* 统计一个目录下所有Java文件的行数
*/
private void countDir(String sourceDir) throws IOException {
// 检查源目录
File fSourceDir = new File(sourceDir);
if(!fSourceDir.exists() || !fSourceDir.isDirectory()){
System.out.println("源目录不存在");
return;
}
// 遍历目录下的文件或目录
File[] file = fSourceDir.listFiles();
for (int i = 0; i < file.length; i++) {
if (file[i].isFile()) {
if(file[i].getName().toLowerCase().endsWith(".java")){
// System.out.println(file[i].getName());
countLine(file[i]);
}
}
//递归统计代码行数
if (file[i].isDirectory()) {
// 准备统计的文件夹
String subSourceDir = sourceDir + File.separator + file[i].getName();
// 统计子目录
countDir(subSourceDir);
}
}
}
public static void main(String[] args) throws IOException {
TestCountDir tcd = new TestCountDir();
tcd.countDir("d:/sxtjava");
System.out.println(tcd.count);
}
}