标准输入输出流
Java中的标准输入 / 输出分别通过System.in和System.out实现,默认情况下是键盘和显示器
PrintStream类:PrintStream为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
PrintWriter类:向文本输出流打印对象的格式化表示形式。此类实现在 PrintStream中的所有 print方法。它不包含用于写入原始字节的方法。
输入重定向
public class InputStreamDemo {
public static void main(String[] args) throws FileNotFoundException {
FileInputStream inputStream = new FileInputStream(new File("test33.txt"));
//setIn
System.setIn(inputStream);
//System.out.println("请输入内容:");
//默认情况下是从控制台进行获取内容
//但是如果使用setIn方法设置了重定向之后,将从指定文件中获取内容,就不会让你再从键盘输入了
Scanner sc = new Scanner(System.in);
String string = sc.next();
System.out.println(string);
}
}
输出重定向
public class PrintStreamDemo {
public static void main(String[] args) throws FileNotFoundException {
//System.out.println("hello world");
//创建打印流的对象
//注意:默认打印到控制台,但是,如果采用setOut方法进行重定向之后,将输出到指定的文件中
PrintStream print = new PrintStream(new FileOutputStream(new File("test33.txt")));
/*
* static void setErr(PrintStream err)
重新分配“标准”错误输出流。
static void setIn(InputStream in)
重新分配“标准”输入流。
static void setOut(PrintStream out)
重新分配“标准”输出流。
* */
//将标准输出重定向到print的输出流
System.setOut(print);
System.out.println("hello world");
}
}
对象流
在流中流动的数据是对象
将一个对象写入到本地文件中,称为对象的序列化
将一个本地文件中的对象读取出来,称为对象的反序列化
如何使用对象流
ObjectInputStream: 对象输入流
ObjectOutputStream:对象输流
注意:
序列化的对象必须实现Serializable接口,否则不能被序列化
如果将多个对象序列化到本地,可以使用集合(将多个对象添加到集合中,将集合的对象写入到本地文件中,再次读出来,获取到的仍然是集合对象,遍历集合,就可以拿到对象)
对象中不可被序列化的字段:
transient(瞬变)修饰的字段
静态的字段
当你在序列化完对象时,如果再修改了对象中的某些属性,那么在反序列化时,就会出问题,程序会认为这是两个类,解决办法:
在要序列化类中添加字段,保证序列化和反序列化是同一个类
private static final long serialVersionUID = 100L;
public class ObjectStreamDemo {
public static void main(String[] args) {
//objectOutputStreamUsage();
objectInputStreamUsage();
}
// 写:将对象进行序列化
public static void objectOutputStreamUsage() {
//1.实例化一个Person的对象
Person person = new Person("张三", 10, 'B');
//2.实例化一个对象输出流的对象
try {
ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(new File("file/person.txt")));
//3.将对象写入到流中 writeObject
output.writeObject(person);
//4.刷新
output.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 读:反序列化
public static void objectInputStreamUsage() {
//1.实例化对象输入流的对象
try {
ObjectInputStream input = new ObjectInputStream(new FileInputStream(new File("file/person.txt")));
//2.读取 readObject
Object object = input.readObject();
//3.对象的向下转型
if(object instanceof Person) {
Person p = (Person)object;
System.out.println(p);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
注意:在使用对象流的时候,用于初始化对象流的参数只能是字节流(将对象转换为二进制的形式,然后再把二进制写入文件)
RandomAccessFile类
RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek()方法来访问记录,并进行读写了。这些记录的大小不必相同;但是其大小和位置必须是可知的。但是该类仅限于操作文件
即可以读,又可以写,但是要求比较高
区别:
seek(int x) 相对于开始的偏移量,连续写两次,也是从第x个位置开始读取
skipBytes(int x) 跳过的字节个数,连续写两次,相当于从第2x个位置开始读取
public class RandomAccessFileDemo {
public static void main(String[] args) throws IOException {
//write();
read();
}
public static void write() throws IOException {
RandomAccessFile raf = new RandomAccessFile("ran.txt", "rw");
//写入
raf.writeUTF("张三");
raf.writeInt(1);
raf.writeBoolean(true);
raf.writeChar('a');
raf.writeUTF("李四");
raf.writeInt(22);
raf.writeBoolean(true);
raf.writeChar('x');
//关闭
raf.close();
System.out.println("写入完毕");
}
public static void read() throws IOException {
RandomAccessFile raf = new RandomAccessFile("ran.txt", "r");
//设置跳过张三
raf.seek(21); //偏移量
raf.seek(21); //效果一样 每次都是从0开始
raf.skipBytes(21); // 跳过21个字节
raf.skipBytes(21); //相当于跳过了24个字节
//读取
String s = raf.readUTF();
int i = raf.readInt();
boolean b = raf.readBoolean();
char c = raf.readChar();
System.out.println(s + " " + i + " " + b + " " + c);
}
}