Java高级- IO流

13.1.File类的使用

File类的使用
1.File类的一个对象,代表一个文件或一个文件目录(俗称: 文件夹)
2.File类声明在java.io包下
3.File类中涉及到关于文件或文件目录的创建,删除,重命名,修改时间,文件大小等方法,
并未涉及到写入或读取文件内容的操作.若需要读取或写入文件内容,必须用IO流来完成.
4.后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的"终点"(:从哪读或写入到哪,或叫节点,这个点就用File来表示),真的要读写内容了,File类的对象主要指的是一个文件就不是文件目录了

  • File类的实例化

1.如何创建File类的实例
File(String filePath)
File(String filePath, String childPath)
File(File parentFile, String childPath)
2.相对路径: 相较于某个路径下,指明的路径
绝对路径: 包含盘符在内的文件或文件目录的路径
3.路径分隔符:
windows: \
unix: /

@Test
    public void test1(){
        // 构造器1
        File file1 = new File("hello.txt");// 路径相对于当前module
        File file2 = new File("F:\\markdown\\JavaSE\\基础语法\\src\\com\\JavaSenior\\IO\\he.txt");// 第二条斜杠表示避免转义的意思
        // 这里还这是单元测试现在还不需要对应硬盘中的文件,此时就仅仅只是内存层面的对象,还没有涉及到对文件中的数据的操作,现在就理解为内存层面对象而已
        System.out.println(file1);
        System.out.println(file2);
        // 构造器2,在上一层目录下指定的可以是文件也可以是文件目录
        File file3 = new File("F:\\markdown\\JavaSE\\基础语法\\src\\com","JavaSenior");// 上一层目录和下一层目录
        System.out.println(file3);
        // 构造器3: 在file3的目下创建的文件
        File file4 = new File(file3, "hi.txt");
        System.out.println(file4);
    }
  • File类的常用方法
// File类的常用方法
    @Test
    public void test2(){
        File file1 = new File("hello.txt");
        File file2 = new File("F:\\markdown\\IO\\hi.txt");
        // 获取绝对路径
        System.out.println(file1.getAbsolutePath());
        // 获取路径
        System.out.println(file1.getPath());
        //获取名字
        System.out.println(file1.getName());
        // 获取上层文件目录路径,若无返回null
        System.out.println(file1.getParent());
        // 获取文件长度(大小)(即:字节数).不能获取目录长度
        System.out.println(file1.length());
        // 获取最后一次修改时间,毫秒值
        System.out.println(new Date(file1.lastModified()));
        System.out.println();
        System.out.println(file2.getAbsolutePath());
        System.out.println(file2.getPath());
        System.out.println(file2.getName());
        System.out.println(file2.getParent());
        System.out.println(file2.length());
        System.out.println(file2.lastModified());
    }
    // 如下的两个方法适用于文件目录:
    //public String[] list(): 获取指定目录下的所有文件或文件目录的名称数组
    // public File[] listFiles(): 获取指定模流下的所有文件或文件目录的File数组
    @Test
    public void test3(){
        File file = new File("F:\\markdown\\JavaSE");
        String[] list = file.list();// 获取下一层目录或文件
        for (String s : list) {
            System.out.println(s);
        }
        File[] files = file.listFiles();// 以绝对路径方式获取下一层文件或目录
        for (File f : files) {
            System.out.println(f);
        }
    }
    /*
    public boolean renamTo(File dest): 把文件移动到指定文件路径并重命名
    比如: file1.renameTo(file2)为例:
    要想保证返回true,要file1在硬盘中是存在的,且file2不能在硬盘中存在
     */
    @Test
    public void test4(){
        File file1 = new File("hello.txt");
        File file2 = new File("F:\\markdown\\IO\\hi.txt");
        boolean renameTo = file1.renameTo(file2);
        System.out.println(renameTo);
    }
    @Test
    public void test5(){
        File file1 = new File("hello.txt");
        System.out.println(file1.isDirectory());//是否为文件目录
        System.out.println(file1.isFile());// 是否为文件
        System.out.println(file1.exists());//是否真正在硬盘中存在
        System.out.println(file1.canRead());//是否可读
        System.out.println(file1.canWrite());//是否可写
        System.out.println(file1.isHidden());//是否隐藏
        // 判断文件呢目录
        File file2 = new File("F:\\markdown\\IO");
        System.out.println(file2.isDirectory());
        System.out.println(file2.isFile());
        System.out.println(file2.exists());
        System.out.println(file2.canRead());
        System.out.println(file2.canWrite());
        System.out.println(file2.isHidden());
    }
    @Test
    public void test6() throws IOException {
        File file1 = new File("hi.txt");
        // 如果不存在
        if (!file1.exists()) {
            // 创建文件.若文件真实存在硬盘中,则不创建,返回false
            file1.createNewFile();
            System.out.println("创建成功");
        }else{// 文件存在
            // 删除磁盘中的文件或文件目录,java中的删除不走回收站
            file1.delete();
            System.out.println("删除成功");
        }
    }
    @Test
    public void test7(){
        // 文件目录(夹)的创建
        File file1 = new File("F:\\markdown\\IO\\IO1\\IO3");// 上一层目录存在
        // 创建文件目录.如果此文件目录存在,就不创建了.如果此文件目录的上层目录不存在,也不创建
        boolean mkdir = file1.mkdir();
        if (mkdir) {
            System.out.println("创建成功1");
        }
        File file2 = new File("F:\\markdown\\IO\\IO1\\IO4");
        // 创建文件目录,若上层文件目录不存在,一并创建
        boolean mkdirs = file2.mkdirs();
        if (mkdirs) {
            System.out.println("创建成功2");
        }
        // 文件删除,要想成功,欲删除的文件目录下不能有子目录或文件
        File file3 = new File("F:\\markdown\\IO\\IO1\\IO3");
        System.out.println(file3.delete());
    }

File类的练习

public class FileDemo {
    // 在
    @Test
    public void test1() throws IOException {
        // 创建一个与file同目录下的另一个文件,名为"haha.txt"
        File file = new File("F:\\markdown\\IO\\IO1\\hello.txt");
        File destFile = new File(file.getParent(), "haha.txt");
        boolean newFile = destFile.createNewFile();
        if (newFile) {
            System.out.println("创建成功");
        }
    }
    // 打印出指定目录所有文件名称,包括子文件目录中的文件
    @Test
    public void test4(){
        // 创建目录对象
        File dir = new File("F:\\markdown\\JavaSE");
        printSubFile(dir);
    }
    public static void printSubFile(File dir){
        // 打印目录子文件
        File[] subFiles = dir.listFiles();
        // 循环每个子文件
        for (File f : subFiles) {
            // 判断子文件是否文件目录
            // 是文件夹,递归打印文件目录方法
            if (f.isDirectory()) {
                printSubFile(f);
            }else{
                // 不是文件夹,输出每个文件的绝对地址
                System.out.println(f.getAbsolutePath());
            }
        }
    }
}

13.2.IO流原理及流的分类

image.png
image.png
image.png
  • 字节流: 以一个byte(8bit)为基本单位传输的流;适合处理非文本数据
  • 字符流: 以一个char(两个字节:16bit)为基本单位传输的;适合处理文本数据
  • 节点流: 直接作用在文件上的流
  • 处理流: 作用在已有节点流处理之上的
  • IO流的体系结构

一.流的分类:
1.操作的数据单位: 字节流,字符流
2.数据的流向: 输入流,输出流
3.流的角色: 节点流,处理流
二.流的体系结构

抽象基类 节点流(或文件流) 缓冲流(处理流的一种)
InputStream FileInputStream (read(byte[] buffer)) BufferedInputStream (read(byte[] buffer))
OutputStream FileOutputStream (write(byte[] buffer,0,len)) BufferedOutputStream (write(byte[] buffer,0,len))/ flush()
Reader FileReader (read(char[] cbuf)) BufferedReader (read(char[] cbuf))
Writer FileWriter (write(char[] cbuf,0,len)) BufferedWriter (write(char[] cbuf,0,len))/ flush()

13.3.节点流(或文件流).

  • FileReader读入数据的基本操作
public class FileReaderWriterTest {
    public static void main(String[] args) {
        // 用绝对路径可以无视main和单元测试
        // 相较于当前工程: F:\markdown\JavaSE\hello.txt
        File file = new File("hello.txt");
        System.out.println(file.getAbsolutePath());
        File file1 = new File("IO\\hello.txt");// 地址这要写就可以相较于当前module下
        System.out.println(file1.getAbsolutePath());
    }
    /*
    将IOmodule下的hello.txt文件内容读入程序中,并输出到控制台,实现读取硬盘中文件的操作
    说明点:
    1.read()的理解: 返回读入的一个字符.如果达到文件末尾,返回-1
    2.异常处理: 为了保证流资源一定可以执行关闭操作.要使用try-catch-finally处理
    3.读入的文件一定要存在,否则就会报FileNotFoundException
     */
    @Test // 单元测试,归具体的module所有
    public void testFileReader() {
        // 异常处理用try-catch比throws好,假如流的对象创建好了没有抛异常,但是下面read的时候出现阻塞读不过来抛了一个IOException
        // 出现了异常就会创建一个异常对象,默认情况下就抛出程序了,相当于程序后面就不执行了,这个时候流就没关,资源就浪费了,存在内存泄露
        // 为了保证即使出现了read异常也要能执行流的资源能执行关闭操作,所以不要用过throws处理,流资源的关闭放在finally是为了防止中途return退出
        FileReader fr = null; // 因为外部要使用,所以这里要先定义
        try {
            // 1.实例化File类的对象,指明要操作的文件
            File file = new File("hello.txt");// 相较于当前module:F:\markdown\JavaSE\基础语法\hello.txt
            // 2.提供具体的字符流来操作文件,相当于给文件提供一个管道来输出数据
            fr = new FileReader(file);// 参数提供文件的路径或名字,上面的file文件一定要存在,否则就会报异常
            // 打开管道的开关,让数据流出
            // 3.数据的读入
            // read(): 返回读入的一个字符.如果达到文件末尾,返回-1,读的是char类型但返回的是字符的int型值
            // int data = fr.read();// 读取文件返回单个字符,文件读完(读取字符末尾结束时)返回-1,文件有多个字符就要用到循环
            // 如果文件是空的,上来就是-1,所以先要做判断,并且有好多字符要读,用while循环
        /*while (data != -1) {
            // 以字符形式输出每个字符
            System.out.print((char) data);
            // 再读一个看看是不是-1
            data = fr.read();//像迭代器一样
        }*/
            // 方式二: 把方法直接写到循环体表达式汇总
            int data;
            while ((data = fr.read()) != -1) {
                System.out.println((char) data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 4.手动关闭流的操作,防止内存泄露
        /*try {
            // 假如文件流对象没有实例化出现了异常,这里关闭会出现空指针异常,所以造了对象才要关闭
            if (fr != null)
                fr.close();
        } catch (IOException e) {
            e.printStackTrace();
        }*/
        // 或
        if (fr != null) {
            try {
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
  • FileReader使用read(char[ ] cbuf)读入数据
// 对read()操作升级: 使用read的重载方法
    @Test
    public void testFileReader1() {
        FileReader fr = null;
        try {
            // 1.File类的实例化(创建文件)
            File file = new File("hello.txt");
            // 2.FileReader流的实例化(创建读取文件的流对象)
            fr = new FileReader(file);
            // 3.读入的操作
            // read(char[] cubf): 返回每次到底写入cbuf数组中的字符的个数.如果达到文件末尾,返回-1
            // 先创建一个数组用来缓存要读数据的个数
            char[] cbuf = new char[5];// 可以存放5个字符的数组
            int len;// 定义每次读数据的个数
            // 判断每次读数据的个数,并且每读一次数据都会覆盖一次数组,可以理解为数组元素的替换
            while ((len = fr.read(cbuf)) != -1) {
                // 如果遍历的长度为cbuf.length,输出的结果就是123ld,因为最后一次只有3个字符,无法完全覆盖上一次 最后2个字符就留下了,所以不能是
                // 方式一:
                // 错误的写法
            /*for (int i = 0; i < cbuf.length; i++) {

            }*/
                // 正确写法: 每次读进去几个就遍历几个,不要过多的取后面的
                /*for (int i = 0; i < len; i++) {
                    System.out.print(cbuf[i]);
                }*/
                // 方式二:
                // 错误,对应着方式一的错误写法
                // 这里cbuf第三次读取还是保留最后的ld的,相当于数组有什么就全取出来了,其实跟cbuf.length一样
                /*String str = new String(cbuf);// char型数组转成String型数组
                System.out.print(str);*/
                // 正确写法: 用String的重载构造器,从头开始取,取到第len个
                String str = new String(cbuf, 0, len);
                System.out.println(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally { // 写在finally里防止try的时候return
            // 4.资源的关闭
            try {
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
  • FileWriter写出数据的操作

从内存中写出数据到硬盘的文件里
说明:
1.输出操作,对应的File可以不存在的.
File对应的硬盘中的文件若不存在,在输出过程中,会自动创建此文件
若存在:
如果流用的构造器是: FileWriter(file,false) / FileWriter(file): 会对原有文件进行覆盖
如果流用的构造器是: FileWriter(file,true): 不会对原有文件覆盖, 而是在原有文件基础上追加内容

@Test
    public void testFileWriter() throws IOException {
        FileWriter fw = null;
        try {
            // 1.提供File类的对象,指明写出的文件
            File file = new File("hello1.txt");
            // 2.提供FileWriter类(数据流)的对象,用于数据的写出
            fw = new FileWriter(file, true);// 第二个参数的意思: 是否在原有文件上添加,表示对原有文件的覆盖,默认为false
            // 3.写出操作
            fw.write("have dream\n");
            fw.write("have dream");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                // 4.流资源关闭
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
  • 用FileReader和FileWriter实现文本文件的复制
@Test
    public void testFileReaderFileWriter() {
        FileReader fr = null;
        FileWriter fw = null;
        try {
            // 1.创建File类的对象,指明读取和写出的文件
            // 不能用字符流处理图片等字节数据
            File srcFile = new File("hello.txt");
            File destFile = new File("hello2.txt");
            // 2.创建输入流和输出流的对象
            fr = new FileReader(srcFile);// 对于输入流,文件一定要存在
            fw = new FileWriter(destFile);// 文件可以不存在
            // 3.读入内存和写出硬盘操作
            // 一次读多个先创建一个数组
            char[] cbuf = new char[5];
            int len;// 记录每次读入到cbuf数组中字符的个数
            // 循环读入: fr流对象读入到cbuf数组返回读入了几个 如果不是-1就还有数据
            while ((len = fr.read(cbuf)) != -1) {
                // 把数据写出到硬盘当中
                // 错误:若这样写 每次5个5个就把数据读出来了
                // fw.write(cbuf);
                // 正确: 读进去几个就写出几个
                fw.write(cbuf, 0, len);// 每次从0开始写出len个字符
                // 循环结束返回-1
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            // 4.关闭流资源,建议从下往上关
            // 两个操作并列写就可以了(也可以用finally),因为就算中途出现异常也已经catch掉了,不影响try以外的代码运行,try里面代码出现异常,内部接着往下的才不执行
            try {
                if (fw != null)
                    fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (fr != null)
                    fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
  • 字符流不能处理图片文件的测试

  • 用FileInputStream不能读取文本文件的测试

  • 用FileInputStream和FileOutputStream读写非文本文件

  • 用FileInputStream和FileOutputStream复制文件的测试

13.4.缓冲流

  • 缓冲流(字节型)实现非文本文件的复制

13.5.转换流

  • 转换流概述与InputStreamReader的使用

  • 转换流实现文件的读入和写出

13.6.标准输入输出流

13.7.打印流

13.8.数据流

13.9.对象流

image.png
image.png
  • 对象流序列化与反序列化字符串操作

对象流的使用
1.ObjectInputStream 和 ObjectOutputStream
2.作用:用于存储和读取基本数据类型数据或对象的处理流。他的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来
3.要想一个java对象是可序列化的,需要满足相应的要求。见Person.java

public class ObjectInputOutputStreamTest {
    /*
    序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去
    使用ObjectOutPutStream输出实现
     */
    @Test
    public void testObjectOutputStream(){
        ObjectOutputStream oos = null;
        try {
            // 1.造一个对象处理流包住一个节点流,造文件和流写在一起
            oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
            // 2.写出到磁盘的对象
            // 一开始内存当中有个对象就是这个String,随时可能会被回收,就把他持久化保存起来,
            // 或者可以不生成文件,通过网络把它传出去也行,传出去以后再另外一端又可以把它还原成字符串
            oos.writeObject(new String("我爱天安门"));
            // 显式的刷新操作
            oos.flush();
            oos.writeObject(new Person("王敏", 23));// 被持久化到Object.dat文件里
            oos.flush();
            // 序列化自定义类,该类的属性也全都要可序列化
            oos.writeObject(new Person("张帅", 21,1001,new Account(5000)));
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (oos != null) {
                // 3.流关闭
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /*
    反序列化过程: 将磁盘文件中的对象还原为内存中的一个java对象,或通过网络方式获取到流,把网络中的流的数据还原为java层面的对象
    使用ObjectInputStream来实现
     */
    @Test
    public void testInputStream(){
        ObjectInputStream ois = null;
        try {
            // 1.造文件和流对象
            ois = new ObjectInputStream(new FileInputStream("object.dat"));
            // 2.写出磁盘操作,一般写入的都是同一个类型的
            Object obj = ois.readObject();// 通常往里放的都是同类型的对象
            String str = (String) obj;// 这个对象其实是个字符串所以可以强转
            Person p = (Person) ois.readObject();
            Person p1 = (Person) ois.readObject();
            // 还原为内存层面
            System.out.println(str);
            System.out.println(p);
            System.out.println(p1);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            // 3.流关闭
            try {
                if (ois != null)
                    ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Person类要满足如下的需求,方可序列化
1.要实现标识接口: Serializable
2.当前类要提供一个全局常量: serialVersionUID(版本序列号)
如果不添加这个全局常量,给这个类的对象序列化了,存储在磁盘中,紧接着对Person类修改了,修改后,自动生成的serialVersionUID就变了,
变了再去还原的话就找不到当初序列化的全局常量对应的Person,在还原时候就出问题了(报异常)
3.除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的。(默认情况下,基本数据类型是可序列化的)
补充: ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量
static属于类的资源不归对象所有所以不能序列化,transient是瞬态的
transient:被修饰的成员属性变量不能被序列化
4.对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,
从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。
当其它程序获取了这种二进制流,就可以恢复成原来的Java对象

public class Person implements Serializable {
    public static final long serialVersionUID = 451615182L;
    private static String name;
    private transient int age;
    private int id;
    private Account acct;// 自定义类属性也要是可序列化的,
    public Person(String name, int age, int id, Account acct) {
        this.name = name;
        this.age = age;
        this.id = id;
        this.acct = acct;
    }

    public Person(String name, int age, Account acct) {
        this.name = name;
        this.age = age;
        this.acct = acct;
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", acct=" + acct +
                '}';
    }
}
class Account implements Serializable{
    // 加上唯一的全局静态常量避免反序列化报异常
    public static final long serialVersionUID = 4515182L;
    private double balance;
    public Account(double balance) {
        this.balance = balance;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    @Override
    public String toString() {
        return "Account{" +
                "balance=" + balance +
                '}';
    }
}

13.10.随机存取文件流

RandomAccessFile的使用
1.RandomAccessFile直接继承于java.Lang.Object类,实现了DataInput和DataOutput接口
2.RandomAccessFile既可以作为一个输入流,又可以作为一个输出流
3.如果RandomAccessFile作为输出流时,写出到的文件若不存在,则在执行过程中自动创建
若写出到的文件存在,则会对原有文件内容进行覆盖.(默认情况下,从头覆盖,能覆盖多少算多少)
4.可以通过把指定指针位置后的内容缓存起来,然后再在指定指针位置插入新值,再把缓存的内容追加回原来的文件,实现RandomAccessFile"插入"数据的效果

public class RandomAccessFileTest {
    @Test
    public void test11() throws FileNotFoundException {
        RandomAccessFile raf1 = null;
        RandomAccessFile raf2 = null;
        try {
            // 1.造流的对象
            raf1 = new RandomAccessFile(new File("pic.jpg"), "r");// 只读模式
            raf2 = new RandomAccessFile(new File("pic3.jpg"), "rw");// 可读可写模式
            // 2.读入写出操作
            byte[] buffer = new byte[1024];
            int len;
            while ((len = raf1.read(buffer)) != -1) {
                raf2.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            // 3.流关闭
            if (raf2 != null) {
                raf2.close();
            }
            if (raf1 != null) {
                raf1.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Test
    public void test2() throws IOException {
        // 创建写出流的对象和文件对象
        RandomAccessFile raf1 = new RandomAccessFile("hello4.txt", "rw");
        // 写出操作
        raf1.seek(3);// 将指针调到角标为3的位置
        raf1.write("xyz".getBytes());// 覆盖掉原来文件里的头三个字符
        // 流关闭
        raf1.close();
    }
    /*
    用RandomAccessFile实现数据的插入效果
     */
    @Test
    public void test3() throws IOException {
        RandomAccessFile raf1 = new RandomAccessFile("hello4.txt", "rw");
        raf1.seek(3);// 将指针调到下标为3的位置
        // 将读取的数据存入一个数组,将数组长度先设置为文件长度的大小避免扩容,提高效率,length()返回一个long类型的值
        // 保存指针角标3后面的所有数据到StringBuilder中
        StringBuilder builder = new StringBuilder((int) new File("hello4.txt").length());//新造数组的大小要么比原文件小,要么和源文件一样大
        // 读取操作
        byte[] buffer = new byte[20];
        int len;
        while ((len = raf1.read(buffer)) != -1) {
            // 把每次遍历的字符放入builder数组中
            builder.append(new String(buffer, 0, len));
        }
        // 此时指针自动跑到最后了,将指针调回角标为3的位置
        raf1.seek(3);
        // 插入"xyz"的数据,相当于对原有内容进行覆盖
        raf1.write("xyz".getBytes());// 这里write返回byte[]类型,所以要用getBytes()
        // 写出后不用再调指针了,指针已经在z的后面了
        // 将builder中的数据写入到文件中
        raf1.write(builder.toString().getBytes());
        // 关闭流
        raf1.close();
    }
}

13.11.NIO.2中Path,Paths,Files类的使用

  • 用第三方jar包实现数据读写

14.1.网络编程概述

14.2.网络通信要素概述

14.3.通信要素1: IP和端口号

  • 端口号的理解
image.png
public class InetAddressTest {
    public static void main(String[] args) {
        // 创建一个对象,其对应的ip就是方法的参数
        // 类似于File file = new File("hello.txt");
        // 内存中的file对象对应着hello.txt路径的文件
        try {
            InetAddress inet1 = InetAddress.getByName("192.168.10.14");// 参数host代表主机名
            System.out.println(inet1);
            InetAddress inet2 = InetAddress.getByName("www.taobao.com");
            System.out.println(inet2);
            InetAddress inet3 = InetAddress.getByName("127.0.0.1");
            System.out.println(inet3);
            // 直接获取本地IP地址的方法
            InetAddress inet4 = InetAddress.getLocalHost();
            System.out.println(inet4);
            // getHostName(): 获取域名
            System.out.println(inet2.getHostName());
            // getHostAddress(): 获取主机地址
            System.out.println(inet2.getHostAddress());
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }
}

14.4.通信要素2: 网络协议

  • TCP和UDP网络通信协议的对比
  • 三次握手: 应该这样理解:1.A发送请求 2.B告诉A已经收到请求(ACK确认)3.A确认B收到了A的请求 4.A开始数据传输

14.5.TCP网络编程

  • TCP网络编程例题:

14.6.udp网络编程

  • UDP编程举例

14.7.url编程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容