IO操作深入(阿里云开发者社区)

# 字符编码

在计算机的世界里面只认0,1的数据,如果要想描述一些文字的编码就需要对这些二进制的数据进行组合,所以才有了现在可以看见的中文,但是在进行编码的时候如果要想正确显示出内容则一定需要有解码,所以编码和解码肯定要采用统一的标准,如果不统一的时候就会出现乱码。

那么在实际的开发之中对于常用的编码有如下几种:
‒ GBK/GB2312:国标编码,可以描述中文信息,其中GB2312只描述简体中文,而GBK包含有简体中文与繁体中文
‒ ISO8859-1:国际通用编码,可以用其描述所有的文字信息,如果象形文字则需要进行编码处理
‒ UNICODE编码:采用十六进制的方法存储,可以描述所有的文字信息
‒ UTF编码:象形文字部分使用16进制编码,而普通的字母采用的是ISO8859-1编码,它的优势在于适合于快速的传输,节约带宽,也就成为了我们在开发之中首选的编码,主要使用UTF-8编码

如果要想知道当前系统中支持的编码规则,则可以采用如下代码列出全部的本机属性

范例:列出本机属性

public class JavaAPIDemo{
public static void main(String args[]){
System.getProperties().list(System.out);
}
}

部分信息:
【文件路径分隔符】file.seperator=
【文件默认编码】file.encoding=UTF-8

也就是说现在什么都不设置的话,则采用的编码就是UTF-8

范例:编写程序

public class JavaAPIDemo{
public static void main(String args[]) throws Exception{
OutputStream output = new FileOutputStream("D:" +File.separator+"mldn.txt");
output.write("xxxxxxxx".getBytes()); // output.write("xxxxxxxx".getBytes("UTF-8"));
output.close();
}
}

此时为默认的处理操作,不设置编码的时候就将采用默认的编码方式进行

范例:强制设置编码
import java.io.*;

public class JavaAPIDemo18 {
    public static void main(String[] args) throws IOException {
//        System.getProperties().list(System.out);
        OutputStream outputStream = new FileOutputStream("."+ File.separator+"IO深入研究"+File.separator+"text.txt");
        outputStream.write("回家吃饭".getBytes("ISO8859-1"));
        outputStream.close();
    }
}
}//????

项目中出现的乱码问题就是编码和解码标准不统一,而最好的解决乱码的方式,所有的编码都用UTF-8

内存操作流

在之前使用的全部都是文件操作流,文件操作流的特点,程序利用InputStream读取文件内容,而后程序利用OutputStream向文件输出内容,所有的操作都是以文件为终端的

假设说现在需要实现IO操作,可是又不希望产生文件(临时文件)则就可以以内存为终端进行处理。

在Java里面提供有两类的内存操作流:
‒ 字节内存操作流:ByteArrayOutputStream,ByteArrayInputStream

‒ 字符内存操作流:CharArrayWriter,CharArrayReader

下面以ByteArrayOutputStream和ByteArrayInputStream类为主进行内存的使用分析,首先分析各自的构造方法:
‒ ByteArrayInputStream:public ByteArrayInputStream​(byte[] buf)
‒ ByteArrayOutputStream:public ByteArrayOutputStream()

在ByteArrayOutputStream类里面有一个重要的方法,这个方法可以获取全部保存在内存流中的数据信息,该方法为:
‒ 获取数据:public byte[] toByteArray​()
‒ 使用字符串的形式来获取:public String toString​()
范例:利用内存流实现小写字母转大写字母操作
文件:写进去读出来
内存:都进去写出来

import java.io.*;

public class JavaAPIDemo19 {
    public static void main(String[] args) throws IOException {
        String str ="www.baidu.com";
        InputStream inputStream = new ByteArrayInputStream(str.getBytes());
        OutputStream outputStream = new ByteArrayOutputStream();
        int data = 0;
        while ((data=inputStream.read())!=-1) outputStream.write(Character.toUpperCase(data));
        System.out.println(outputStream);
        inputStream.close();
        outputStream.close();
    }
}

如果现在不希望只是以字符串的形式返回,因为可能存放的是其他二进制的数据,那么此时就可以利用ByteArrayOutputStream子类的扩展功能获取全部数据

import java.io.*;

public class JavaAPIDemo20 {
    public static void main(String[] args) throws IOException {
        String str ="www.baidu.com";
        InputStream inputStream = new ByteArrayInputStream(str.getBytes());
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        int data = 0;
        while ((data=inputStream.read())!=-1) outputStream.write(Character.toUpperCase(data));
        System.out.println(outputStream.toString());
        System.out.println(outputStream);
        inputStream.close();
        outputStream.close();
    }
}

在最初的时候可以利用ByteArrayOutputStream实现大规模文本文件的读取。

管道流

管道流主要的功能是实现两个线程之间的IO处理操作

对于管道流也是分为两类:
‒ 字节管道流:PipedOutputStream,PipedInputstream
‒ 连接处理:public void connect​(PipedInputStream snk)throws IOException
‒ 字符管道流:PipedWriter,PipedReader
‒ 连接处理:public void connect​(PipedReader snk)throws IOException
范例:实现管道操作

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class JavaAPIDemo21 {
    public static void main(String[] args) throws IOException {
        SendThread sendThread = new SendThread();
        ReceiveThread receiveThread = new ReceiveThread();
        sendThread.getOutputStream().connect(receiveThread.getInput());
        new Thread(sendThread,"消息接受线程").start();
        new Thread(receiveThread,"消息接收线程").start();
    }
}
class SendThread implements Runnable{
    private PipedOutputStream outputStream;
    public SendThread(){
        this.outputStream = new PipedOutputStream();
    }
    public void run(){
        for (int i = 0; i < 10; i++) {
            try {
                this.outputStream.write(("[第"+(i+1)+"次]"+"[信息发送 - "+Thread.currentThread().getName()+"]www.baidu.com\n").getBytes());
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        try {
            this.outputStream.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
    public PipedOutputStream getOutputStream(){
        return outputStream;
    }
}

class ReceiveThread implements  Runnable{
    private PipedInputStream  input;
    public ReceiveThread(){
        this.input = new PipedInputStream();
    }
    public void run(){
        byte data[] = new byte[1024];
        int len = 0;
        ByteArrayOutputStream bos = new ByteArrayOutputStream(); // 所有的数据保存到内存输出流
        try{
            while((len = this.input.read(data))!=-1){
                bos.write(data,0,len); // 所有的数据保存到内存流里
            }
            System.out.println("{"+Thread.currentThread().getName()+"接收消息}\n"+new String(bos.toByteArray()));
            bos.close();
        }catch(IOException e){
            e.printStackTrace();
        }
        try{
            this.input.close();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
    public PipedInputStream getInput(){
        return this.input;
    }
}

管道就类似于医院打点滴的效果,一个只负责发送,一个负责接收,中间考一个管道连接

RandomAccessFile

对于文件内容的处理操作主要是通过InputStream(Reader),OutputStream(Writer)来实现,但是利用这些类实现内容读取,只能够将数据部分部分读取进来,如果说现在有这样一种要求。

现在给了你一个非常庞大的文件,这个文件的大小有20G,如果此时按照传统的IO操作进行读取和分析根本就不可能完成,所以这种情况下java.io包里面就有一个RandomAccessFile类,这个类可以实现文件的跳跃式的读取,可以只读取中间的部分内容(前提:需要有一个完善的保存形式),数据的保存位数要都确定好。

模型变了,空格加在前面
RandomAccessFile类里面定义有如下的操作方法:
‒ 构造方法:public RandomAccessFile​(File file,String mode) throws FileNotFoundException
‒ 文件的处理模式:r,rw;

RandomAccessFile最大的特点是在于数据的读取处理上,因为所有的数据是按照固定的长度进行保存,所以读取的时候就可以进行跳字节读取:
‒ 向下跳:public int skipBytes​(int n) throws IOException
‒ 向回跳:public void seek​(long pos)throws IOException

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;

public class JavaAPIDemo22 {
    public static void main(String[] args) throws IOException {
        File file = new File("."+File.separator+"IO深入研究"+File.separator+"message2.txt");
        RandomAccessFile raf = new RandomAccessFile(file,"rw");
        String[] names = new String[]{"zhangsan","wangwu","lisi"};
        int[] ages = new int[]{30,20,16};
        for (int i = 0; i < names.length; i++) {
            raf.write(names[i].getBytes());
            raf.writeInt(ages[i]);
        }
        raf.close();

        RandomAccessFile raf2 = new RandomAccessFile(file,"rw"); // 读写模式
        { // 读取“李四的数据,跳过24位
            raf2.skipBytes(22);
            byte [] data = new byte[4];
            int len = raf2.read(data);
            System.out.println("姓名:"+new String(data,0,len)+"\t年龄\t" + raf2.readInt());
        }
        { // 读取“王五的数据,回跳12位
            raf2.seek(12);
            byte [] data = new byte[6];
            int len = raf2.read(data);
            System.out.println("姓名:"+new String(data,0,len)+"\t年龄\t" + raf2.readInt());
        }
        { // 读取“张三的数据,回跳0位
            raf2.seek(0); //回到顶点
            byte [] data = new byte[8];
            int len = raf2.read(data);
            System.out.println("姓名:"+new String(data,0,len)+"\t年龄\t" + raf2.readInt());
        }
    }
}

整体的使用之中由用户自行定义要读取的位置,然后按照指定的结构进行数据的读取

学习资料

阿里云开发者社区

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值