Java泛型I/O流网络

1、泛型

1.1概述

  • JDK5.0的新特性 本质上 泛型就是编译期的行为,当程序加载到JVM中时,就是确定类型的 也就是说只有在创建对象时才能真正的确定类型,所以说泛型不能用在静态的结构中(属性,方法) 因为静态的结构是在加载时就确定了数据类型,而真正的确定泛型的类型是在运行期

  • 就是允许在定义类、接口时通过一个标识标识类中的某个属性的类型或者是某个方法的返回值类型参数类型,这个类型参数将在使用时(例如继承或实现这个接口使用这个类型声明变量创建对象时)确定(即传入实际的类型参数,也称为类型实参)

  • 泛型只能是引用数据类型 不能是基本数据类型

  • 使用时没有指定泛型的具体类型,默认为Object类型

  • 在创建对象指定泛型类型时,可以只在类型的声明处带上具体的类型,后面可以不写

    Map<String,String> map = new HashMap<String,String>();//标准写法
    
    //JDK8新特性 类型推断 后面的类型可以省略 <>也可以省略 
    Map<String,String> map = new HashMap();
    
  • 如果想要使用多个泛型,<A,B,C> 用逗号隔开

  • 泛型不同的引用不能相互赋值

    ArrayList<Integer> list1 = new ArrayList();
    ArrayList<String> list2 = new ArrayList();
    //错误 虽然说list1和list2数据类型相同,但是他俩的泛型类型不同 不可相互赋值
    list1 = list2; 
    
  • 经验:泛型要么一路都用,要么一路都不用

  • 父类有泛型,子类可以选择保留泛型也可以选择指定泛型的类型,也可以额外的定义泛型

  • 在JDBC/Mybatis&Plus的开发中,大量使用泛型,MybatisPlus的核心原理之一就是泛型,先定义了一个BaseXX ,里面定义了一些方法,然后不同的类去继承这个类,传入我们指定的泛型,那么就操作的是我们的类

    MybatisPlus的源码及应用①

    public interface BaseMapper<T> extends Mapper<T> {
        
        int insert(T entity);
    	
        int deleteById(Serializable id);
    
    
        int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
    
       ...很多的方法规范 这就相当是一个通用的mapper接口,定义了方法规范,我们自定义的
           接口只需要继承此接口接口,重要的是我们要传入我们的实体类
    }
    
    -----------------------
       然后 我们
        @Mapper
    public interface WareInfoDao extends BaseMapper<WareInfoEntity> {
    
    }
    
    

    MybatisPlus的源码及应用②

    ​ 为什么我们只要导入了MybatisPlus的依赖,基本的增删改查都不用写了呢?

    //第一点 通用的ServiceImpl 里面把基本的增删改查全都实现了
    //我们在使用时只需要继承此类,传入我们的泛型即可
    @SuppressWarnings("unchecked")
    public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> { 
        
        //我们只需要继承此通用Impl即可 传入指定的泛型 
    @Service("wareSkuService")
    public class a extends ServiceImpl<aDao, aEntity> implements aServie {   
    

1.2自定义泛型使用

泛型类/泛型接口

public class Result<T> {
    private T data; 
    
    public T say(){
        xxx...
    }
}

//这个子类在定义时指明了父类泛型的类型 那么子类就不是一个泛型类
public class SubResult extends Result<Integer>{
}

//子类在定义时没有指明父类的泛型类型 那么子类还是一个泛型类
public class SubResult1<T> extends Result<T>{    

}	

泛型方法

1、在方法中出现了泛型的机构,但用的不是类或接口中定义的泛型,跟类或接口的泛型没有关系 没有泛型属性这一说

2、泛型方法可以是静态的,因为泛型方法的类型是在调用方法的时候才确定的 而非泛型方法(使用类上定义的泛型)在运行期才确定数据类型
3、泛型方法如果返回值用到了泛型的话一般的都在方法参数中也是用泛型,因为在调用的时候传入这个参数时就确定泛型的类型

public class Test<T> {
	
    //非泛型方法 使用了类上的泛型
    public T say(){
        xx
    }
    
    //这是一个泛型方法 这里的泛型跟T没有关系 独立的 
    //注意格式 使用前要声明 <E>
    //泛型方法可以是静态的
    //返回值用到了泛型 所以在参数中必须使用泛型
    public static <E> List<E> change(E[] arr) {
        ArrayList<E> list = new ArrayList();
        for (E e : arr) {
            list.add(e);
        }
        return list;
    }

    public static void main(String[] args) {
        Integer[] arr = new Integer[]{1,23,4,34,2};
        List<Integer> change = change(arr);
        System.out.println(change);
    }
}

通配符 ?

  • 假设类A是类B的父类,G 和 G 两者不具备子父类关系,且不能相互赋值
List<String> list1 = null;
List<Object> list2 = null;

list2= list1; //错误 虽然说String是Object的父类,但是他俩在泛型上,就没有多态性
	

public class A>{

    public static void main(String[] args) {
        List<Integer> listIn = null;
        List<String> listSt = null;
        //te(listIn);  错误 
        //te(listSt) 错误
     
    
    public static void te(List<Object> list){
        
    }    
}

/*
 反证法:假设 list2可以赋给list1 那么就导致混入非String的数据 
*/

所以就引入通配符 ? 使用了通配符后任何的同类型不同泛型可以传入,也可以不写泛型

public static void main(String[] args) {
    List<Integer> listIn = null;
    List<String> listSt = null;
    //te(listIn);  错误 
    //te(listSt) 错误
}
public static void te(List<?> list){
    
}    
//不能增加数据
List<?> list= null;
list.add(null);
//list.add("sad"); //错误 不能增加数据

允许读取数据
   List<?> list = null;
   Object o = list.get(2);

有限制条件的通配符
  • <? extends A>

    只能是A或A的子类(或者是A的实现类)

  • <? super B>

    只能是B或者B的父类

2、I/O流

我们通常使用集合,数组存储数据,这些数据都是在内存中的,只要我们的JVM关闭(程序运行结束),这些数据都没有了,所有我们就要使用IO流,将内存中的数据持久化到硬盘中(输出流),也能将硬盘中的数据读到内存中供我们进行操作(输入流) (读入写出)

2.1File类

2.1.1概述

  • java.io.File类:文件和文件目录路径的抽象表示形式,与平台无关

  • (IDEA)在main方法中写文件的相对路径默认是当前的工程下,在Junit的测试中默认是当前module

  • 只能是对于文件的属性(文件名 位置等)进行操作,不能对文件的内容进行修改(使用IO)

  • 后续在使用IO时,File类的对象基本都当做参数传递到流的构造器中,指明操作的文件

  • 当硬盘中有一个真实文件或者目录存在时,创建file对象时,各个属性会显示赋值,

    当硬盘中没有真实的文件或者目录时,那么创建对象时,除了指定的目录和路径之外,其他的属性都是默认值

在这里插入图片描述

2.1.2File的结构

构造器

不要求在硬盘中存在真实路径的文件,这只是内存层面的一个对象

   //相对路径 在IDEA中默认是当前module中
   //绝对路径 包含盘符在内的文件或者文件目录的路径
	//不需要在硬盘上有真实的文件或者目录,这里仅仅是内存层面的一个对象
   public File(String pathname){}
// (File类型)parent路径下的 child文件夹或者文件
public File( File parent,String child) {}
// 指定在 parent目录下的 child文件或者目录
public File(String parent, String child) {}
常用方法
--------------------------<获取一些信息功能>----------------------------------
public String getAbsolutePath()  //获取绝对路径

public String getPath()      //获取路径
 
public String getName()      //获取名称
  
public String getParent()    //获取文件的上层目录路径,若无,返回null

public long length()         //获取文件长度(字节数) 不能获取目录的长度

public long lastModified()   //获取最后一次的修改时间 毫秒值

public String[] list()       //获取指定目录下的所有文件或者文件目录的名称数组

public File[] listFiles()    //获取指定目录下的所有文件或者文件目录的File数组
    
--------------------------<重命名>-------------------------------------------
    
    //重命名 file1.renameTo(file2) 
    //保证 file1必须存在 且file2不能存在 (如果两个路径不同,是一次移动操作)
public boolean renameTo(File dest)  
    
--------------------------<判断功能>------------------------------------------
    
public boolean isDirectory() //判断是否是文件目录
public boolean isFile()   //判断是否是文件
public boolean exists()   //判断文件是否存在 
public boolean canRead()  //判断是否可读
public boolean canWrite() //判断是否可写
public boolean isHidden() //判断文件是否隐藏
    
--------------------------<创建功能>------------------------------------------
//创建文件 若文件存在则不创建 返回false  一般先使用exists判断一下是否存在
public boolean createNewFile() 
        
//创建文件目录,如果此文件目录存在,就不创建,如果此文件目录的上层目录不存在,也不创建
public boolean mkdir() 

//创建文件目录,如果上层文件目录不存在,一并创建
public boolean mkdirs()    
注意事项:如果你创建文件或者文件目录没有写盘符名称,那么,默认在项目路径下 
    
--------------------------<删除功能>------------------------------------------
//删除文件或者文件夹
public boolean delete()
    注意:Java的删除不走回收站 直接就没了
    要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录 否则删除失败
     

2.2流

2.2.1概述

输入(input)输出(output)的理解:我们应该站在内存的角度来看待输入和输出

将硬盘或者网络中的数据取到内存中是输入 (使用输入流)

将内存中的数据(持久化)到硬盘网络中是输出 (使用输出流)

2.2.2流的分类

  • 根据操作数据单位的不同分为: 字节流 字符流

​ 字节流一般用来处理视频音频等,字符流用于处理文本文件

  • 根据数据流的流向不同分为:输入流,输出流

  • 按照流的角色不同分为:节点流,处理流

    节点流就是直接处理数据的流,处理流就来处理节点流的(比如缓冲流,转换流)等

2.2.3流的体系

在这里插入图片描述

2.2.4不同的文件的处理情况

  • 对于文本文件(.txt .java .c .cpp等,使用字符流处理
  • 对于非文本文件(.jpg .mp3 .mp4 .avi .doc .ppt 等)只能使用字节流处理
  • 如果是纯复制操作,不涉及显示文件内容,文本文件也可以使用字节流处理

2.2.5常用流及其方法

抽象基类节点流缓冲流(一种处理流)
ReaderFileReader_read(char[] c)BufferedReader_readLine()
WriterFileWriter_write(char[] c,0,len)BufferedWriter_write(String str)_newLine()
InputStreamFileInputStream_read(byte[] b)BufferedInputStream_read(byte[] b)
OutputStreamFileOutputStream_write(byte[] b,len)BufferedOutputStream_write(byte[] b,len)

2.2.6字符集

P_601

2.2.7练习统计字符出现的个数

@Test
public void test2() throws Exception {
    FileReader fr = new FileReader("计数文件");
    BufferedReader br = new BufferedReader(fr);
    FileWriter fw = new FileWriter("计数1文件");
    BufferedWriter bw = new BufferedWriter(fw);
    Map<Character, Integer> map = new HashMap();
    String temp = null;
    while ((temp = br.readLine()) != null) {
        char[] chars = temp.toCharArray();
        for (char c : chars) {
            if (map.containsKey(c)) {
                Integer count = map.get(c);
                map.put(c, count + 1);
            } else {
                map.put(c, 1);
            }
        }
    }
    Set<Map.Entry<Character, Integer>> entries = map.entrySet();
    for (Map.Entry<Character, Integer> entry : entries) {
        String data = entry.getKey() + "出现 " + entry.getValue() + "次";
        bw.write(data);
        bw.newLine();
    }
    bw.close();
    fw.close();
}

2.3字符流(Reader/Writer)

2.3.1字符类概述

  • 字符流都是以(xxxReader或xxxWriter)结尾的
  • 处理纯文本文件使用字符流(doc文件不属于纯文本文件)

2.3.2节点流

2.3.2.1输入流FileReader
2.3.2.1.1基本读取read()方法
  • read()方法

    返回值是每个字符对象的编码值,自动的带有类似的指针功能,读取之后自动指向下一个字符,如果读到了文件的末尾,返回 -1

public int read() throws IOException(){}
@Test
public void test1() {
       FileReader fr = new FileReader("hello.txt");
       int data;
        //返回读入的一个字符,自动把char类型转成了int类型,想要看到字符需要强转
        //如果到末尾,返回-1
        //read()方法类似有指针的功能 读完一个判断如果下一个位置还有字符的话,自动的指向一个位置的字符
        while ((data = fr.read()) != -1) {
            System.out.print((char) data);
        }
}
2.3.2.1.2read(char[] cubf)读取
  • 上面的方法,是一个一个字符进行读取,要跟硬盘进行多次交互,效率十分低下,用重载的方法
  • 一次读取指定长度的字符,返回值是每次读取到的字符的长度,当读到末尾时返回-1
    @Test
    public void test2() throws Throwable {
        FileReader fr = new FileReader("hello.txt");
        char[] data = new char[5];
        int len; //定义一个变量 表示每次读取到的字符的个数
        while ((len = fr.read(data))!=-1) {
        //注意这里一定要指定字符的长度是每次读取到的字符的长度,不然会出问题
          String str = new String(data,0,len);
          System.out.println(str);
       //   -----第二种方式 终止条件一定是小于len 不能是数组的长度
       //     for (int i = 0; i < len; i++) {
       //         System.out.println(data[i]);
            }  
        }
    }

原理就是每次读取指定个数的字符,下一次读取的字符会覆盖前面字符数组中的字符,所以说,下面两种写法是错误的,

有可能最后一次读取的字符个数没有达到数组的长度,那么不会将上一次的数组中的数据全部覆盖,就会问题,
           for (char c : data) {
                System.out.println(c);
            }
        
----
            for (int i = 0; i < data.length; i++) {
                System.out.println(data[i]);
                
            }
2.3.2.2输出流FileWriter

构造器

//只有文件名,第二个参数append默认是false,会对文件内容进行覆盖
public FileWriter(String fileName)
//一般使用这个构造器,指定第二个参数是true,不会对文件内容进行覆盖    
public FileWriter(String fileName, boolean append)

方法

直接调用write方法即可进行写操作

public void write(String str)
public void write(char cbuf[], int off, int len) 
应用_复制文件
@Test
public void test() throws Throwable {
    FileReader fr = new FileReader("hello.txt");
    FileWriter fw = new FileWriter("hello1.txt",true);
    char[] datas = new char[1024];
    int length;
    while ((length=fr.read(datas))!=-1){
        //String str = new String(datas, 0, length);
        //fw.write(str);
        fw.write(datas, 0, length);
        fw.flush();
    }
    ...关闭流等操作
}

2.3.3处理流

2.3.3.1缓冲流

作用

提升流的读写效率,并新增了一些方法更加方便处理

内部有一个缓冲区(8192)先读到缓冲区,一次性的写入

2.3.3.1.1输入流BufferedReader

提供了更加方便的API readLine()

2.3.3.1.2输出流BufferedWriter

提供了对应的newLine()换行

应用_复制文件
@Test
public void test2() {
    BufferedReader br = null;
    BufferedWriter bw = null;
    try {
        FileReader fr = new FileReader("pom.xml");
        br = new BufferedReader(fr);

        FileWriter fw = new FileWriter("pom1.xml");
        bw = new BufferedWriter(fw);
        String data = null;
        while ((data = br.readLine()) != null) {
 //读取的一行数据默认是不带换行符的 需要手动的添加换行符或者调用BufferedWriter的newLine()方法手动换行
            System.out.println(data);
            bw.write(data); //写入
            bw.newLine();
        }

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //只关闭缓冲流即可
        if (br != null) {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (bw != null) {

            try {
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
2.3.3.2转换流
2.3.3.2.1概述
  • 转换流提供了在字节流和字符流之间的转换 ,主要作用就是可以指定字符集读写

  • 转换还是属于字符流,看后缀就知道

  • Java提供了两个转换流,

    InputStreamReader:将InputStream转换为Reader(字节输入流字符输入流)

    OutputStreamWriter : 将Writer转换为OutputStream(字符输出流转为字节输出流)

在这里插入图片描述

  • 对应的就是编码和解码的操作

    编码 字符转为字节 而InputStreamReader就是做的这个事,将底层读出的字节转换为指定格式的字符

    解码 字节转字符 OutStreamWriter就是将写入的字符转成字节存储到底层

2.3.3.2.1InputStreamReader

将一个字节输入流转为字符输入流读取到控制台

@Test
public void test1() throws Throwable{

    FileInputStream fis = new FileInputStream("计数1文件");
    //两个参数的构造器,可以指定解码的字符格式
    InputStreamReader isr = new InputStreamReader(fis,"UTF-8");

    char[] datas = new char[20];
    int len;
    while ((len = isr.read(datas))!=-1){
        String str = new String(datas,0,len);
        System.out.print(str);
    }
}
2.3.3.2.1OutputStreamWriter
应用_使用utf-8读,gbk写
@Test
public void test2() throws Exception {

    FileInputStream fis =  new FileInputStream("计数1文件");
    FileOutputStream fos = new FileOutputStream("计数二文件.txt");

    //转换流
    InputStreamReader isr = new InputStreamReader(fis, "utf-8");
    //输出流,以gbk的编码格式写
    OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");

    char[] datas = new char[20];
    int len;
    while ((len = isr.read(datas)) != -1) {
        osw.write(datas, 0, len);
    }
    osw.close();
    isr.close();
}

2.4字节流(Input/OutputStream)

2.4.1节点流

2.4.1.1输入流FileInputStream

read()方法读数据 基本用法跟字符流一样,但是需要造的是字节数组 byte[]

2.4.1.2输出流FileOutputStream

write()方法写数据

应用_复制图片
@Test
public void test1() throws Exception {
    FileInputStream fis = new FileInputStream("异常结构体系.png");
    //构造器跟FileWriter类似,也有一个是否覆盖参数
    FileOutputStream fos = new FileOutputStream("异常结构体系1.png",true);
    byte[] datas = new byte[1024]; //定义字节数组
    int length;
    while ((length = fis.read(datas)) != -1) {
        fos.write(datas,0,length);
    }
    .... 关闭流等操作
}

2.4.2处理流

2.4.2.1缓冲流
2.4.2.1.1输入流BufferedFileInputStream
2.4.2.1.1输出流BufferedFileOutputStream
应用使用缓冲流实现图片的复制
 BufferedInputStream bis = null;
    BufferedOutputStream bos = null;
    try {
        //先关外流  后关内流
        //说明 在关闭外流时,内层流自动就关闭 可以省略关闭内层流的操作
        //flush刷新缓冲区 没有必要添加,读写时自动的添加 但是一定要关闭流,

        FileInputStream fis = new FileInputStream("异常结构体系.png");
        FileOutputStream fos = new FileOutputStream("异常结构体系3.png");

        bis = new BufferedInputStream(fis);
        bos = new BufferedOutputStream(fos);

        byte[] datas = new byte[1024];
        int length;
        while ((length = bis.read(datas)) != -1) {
            bos.write(datas, 0, length);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if (bis != null) {
                bis.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (bos != null) {
            try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

2.5对象流(ObjectInput/OutputStream)

2.5.1对象的序列化机制

  • 序列化:将内存中的Java对象转换成与平台无关的二进制流,从而把这种二进制流持久的保存到到硬盘上或通过网络将这种二进制流传输到网络的另一个节点
  • 反序列化:当一个网络节点或者程序获取到了这个二进制流时,就可以将这个二进制流恢复成原始的Java对象

2.5.3对象流概述

  • 是一种字节处理流,需要装饰字节输入/输出流
  • ObjectInputStream和ObjectOutStream
  • 用于存储和读取基本数据类型数据或者对象的处理流,它的强大之处就是可以把Java中的对象写入到数据源中,也能将对象从数据源中还原回来
  • 序列化:使用ObjectOutputStream类来保存基本类型数据或对象的机制
  • 反序列化:使用ObjectInputStream类读取基本类型数据或对象的机制
  • static或者transient修饰的成员变量不能被序列化,其值都是默认值

2.5.2如何将对象序列化及反序列化

`要求:

  • 对象所在的类必须实现java.io.Serializable接口才能被序列化
  • 提供一个全局常量serialVersionUID
  • 除了当前类实现java.io.Serializable接口外,当前类的非基本数据类型成员变量也必须实现java.io.Serializable接口
class Person implements Serializable {

    //作为一个类的唯一标识 作用是在反序列化时进行对比serialVersionUID是否相同
    //如果没有加serialVersionUID,那么系统会默认的生成一个,但是如果你修改了这个类,
    //那么serialVersionUID会发生变化,那么在反序列化的过程中就会出现异常
   private static final long serialVersionUID = -1231232121312321342L;
   
   //Account类必须也实现Serializable接口
   private Account account;
   private String name;
  
}

class Account implements Serializable{
    private static final long serialVersionUID = -1312327777888921342L;
    private double money;   
}

2.5.3使用对象流将对象序列化及反序列化

    @Test
    public void test() throws Throwable {
		
        //将内存中的数据输出到硬盘或者网络 使用ObjectOutputStream
        FileOutputStream fos = new FileOutputStream("obj.txt",true);
        ObjectOutputStream oos = new ObjectOutputStream(fos);

        Person p1 = new Person(new Account(133), "zhangsan");
        Person p2= new Person(new Account(233), "lisi");
        Person p3 = new Person(new Account(333), "wangwu");

        List<Person> list = new ArrayList();
        list.add(p1);
        list.add(p2);
        list.add(p3);

      oos.writeObject(list);
        oos.close();
    }

    //反序列化从网络或硬盘中读取使用ObjectInputStream 
    //主要使用readObject()方法
    @Test
    public void test2() throws Throwable {
        FileInputStream fis = new FileInputStream("obj.txt");
        ObjectInputStream ois = new ObjectInputStream(fis);
        List<Person> list = (List<Person>) ois.readObject();
        for (Person person : list) {
            System.out.println(person);
        }
        //输出
//Person{account=Account{money=133.0}, name='zhangsan'}
//Person{account=Account{money=233.0}, name='lisi'}
//Person{account=Account{money=333.0}, name='wangwu'}
    }
}

2.6数据流DataInput/Output/Stream

2.6.1概述

  • 为了方便操作Java的基本数据类型和String,可以使用数据流

  • 数据流有两个类,用于读取和写出基本类型和String类型

    DataInputStream和DataOutStream,分别装饰在InputStream和OutputStream的子类上

  • 主要的方法

    readUTF()读字符串
    在这里插入图片描述

2.7标准输入流/打印流

  • System.in和System.out分别代表了系统标准的输入和输出设备,

  • 默认输入设备是键盘,输出设备是显示器

    1System.in是System类的一个静态属性,类型是==InputStream==,就是指定了从控制台读取数据的一个字节输入流

    //相当于这种操作 底层是C++帮我们做的
    InputStream is = new InputStream("控制台");
    

    System.in 标准的输入流

    public final static InputStream in = null;
    

    2System.out是System类的一个静态属性,类型是PrintStream(打印流),是OutputStream的子类,就是指定了将内存中的数据写到控制台中的一个字节输出流

    System.out 标准的输出流

    public final static PrintStream out = null;
    
  • 可以通过System类的setIn()和setOut()方法对默认设备进行改变

练习:自定义一个标准输入流
public class MyInput {

    private static final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    public static int getInt() throws IOException {
        String data = br.readLine();
        return Integer.parseInt(data);
    }

    public static String getString() throws IOException {
        return br.readLine();
    }
}

2.8随机存取文件流RandomAccessFile

2.8.1概述

  • 直接继承java.lang.Object类,实现了DataInput和DataOutput接口

  • 既可以作为一个输入流,也可以作为一个输出流

  • 支持随机访问的模式,程序可以直接跳到文件的任意地方来读写文件

    1、支持只访问文件的部分内容

    2、可以向已存在的文件或追加内容

2.8.2简单的读写

@Test
public void test1简单读() throws IOException {
    //r 表示只读 相当于输入流
    RandomAccessFile raf = new RandomAccessFile("hello.txt", "r");
    byte[] datas = new byte[1024];
    int len;
    while ((len=raf.read(datas))!=-1){
        String s = new String(datas, 0, len);
        System.out.println(s);
    }
    raf.close();
}

@Test
public void test2简单写() throws IOException {
    //rw 相当于输出流
    RandomAccessFile raf = new RandomAccessFile("hello.txt", "rw");
    //会进行覆盖,部分覆盖,写多少覆盖多少
    raf.write("xx".getBytes());
    raf.close();
}

2.8.3实现数据的插入

seek()方法,指定指针位置

p_615

2.9NIo Path Paths Files

P_616

3.网络编程

3.1两个主要问题

1、如何准确的定位网络上一台或多台主机 (IP和端口号)

​ Java中InetAddress类代表IP

​ 端口号代表不同的进程,不同的进程有不同的端口号

​ 端口号与IP地址的组合得出一个网络套接字:Socket

2、找到主机后如何可靠高效的进行数据传输 (提供网络通信协议)

1、支持只访问文件的部分内容

2、可以向已存在的文件或追加内容

2.8.2简单的读写

@Test
public void test1简单读() throws IOException {
    //r 表示只读 相当于输入流
    RandomAccessFile raf = new RandomAccessFile("hello.txt", "r");
    byte[] datas = new byte[1024];
    int len;
    while ((len=raf.read(datas))!=-1){
        String s = new String(datas, 0, len);
        System.out.println(s);
    }
    raf.close();
}

@Test
public void test2简单写() throws IOException {
    //rw 相当于输出流
    RandomAccessFile raf = new RandomAccessFile("hello.txt", "rw");
    //会进行覆盖,部分覆盖,写多少覆盖多少
    raf.write("xx".getBytes());
    raf.close();
}

2.8.3实现数据的插入

seek()方法,指定指针位置

p_615

2.9NIo Path Paths Files

P_616

3.网络编程

3.1两个主要问题

1、如何准确的定位网络上一台或多台主机 (IP和端口号)

​ Java中InetAddress类代表IP

​ 端口号代表不同的进程,不同的进程有不同的端口号

​ 端口号与IP地址的组合得出一个网络套接字:Socket

2、找到主机后如何可靠高效的进行数据传输 (提供网络通信协议)
传输层的两个重要协议

  • 1、传输控制协议TCP
    三次握手 四次挥手在这里插入图片描述

  • 2、用户数据报协议UDP
    在这里插入图片描述

三次握手 四次挥手

TCP网络编程练习

客户端发送内容给服务端 服务端将内容打印到控制台

//TCP网络编程
/**
*  客户端发送信息给服务端
*
* */
@Test
public void client() throws Throwable{
    //创建Socket对象 指明服务器端的Ip和端口号
    InetAddress name = InetAddress.getByName("127.0.0.1");
    Socket socket = new Socket(name,8899);

    //获取一个输出流,用于向服务器写(发送)数据
    OutputStream os = socket.getOutputStream();
    os.write("速度阿萨德sddd速度分代收集看2ad".getBytes());
    //资源关闭 流和网络都要关闭
    os.close();
    socket.close();
}

//服务端
@Test
public void server() throws Throwable{
    //创建一个服务器 指定自己的端口号
    ServerSocket serverSocket = new ServerSocket(8899);

    //调用accept 接受来自客户端的socket
    Socket csocket = serverSocket.accept();

    //获取客户端的ip
    System.out.println("客户端ip域名"+csocket.getInetAddress().getHostName());

    //获取输入流 读取客户端发来的的数据
    InputStream is = csocket.getInputStream();

    char[] datas = new char[20];
    int len;
    //使用转换流转换一下,因为输入使用的是字节流避免乱码 字节转字符
    InputStreamReader isr = new InputStreamReader(is);
    if ((len =isr.read(datas))!=-1) {
        System.out.println(new String(datas,0,len));
    }
}

客户端发送图片给服务器,服务器保存图片到本地

@Test
public void client() throws Throwable{
    //指定服务器ip和端口
    Socket socket = new Socket("127.0.0.1",8989);
    OutputStream os = socket.getOutputStream();
    BufferedOutputStream bos = new BufferedOutputStream(os);
    FileInputStream fis = new FileInputStream("异常结构体系3.png");
    BufferedInputStream bis = new BufferedInputStream(fis);
    byte[] datas = new byte[1024];
    int len;
    while ((len=bis.read(datas))!=-1){
        bos.write(datas,0,len);
    }
    bos.close();
    bis.close();
    socket.close();
}

@Test
public void server() throws Throwable{
    ServerSocket serverSocket = new ServerSocket(8989);
    Socket socket = serverSocket.accept();
    InputStream is = socket.getInputStream();
    BufferedInputStream bis = new BufferedInputStream(is);
    FileOutputStream fos = new FileOutputStream("异常结构体系s.png");
    BufferedOutputStream bos = new BufferedOutputStream(fos);
    byte[] datas = new byte[1024];
    int len;
    while ((len=bis.read(datas))!=-1){
        bos.write(datas,0,len);
    }
        bos.close();
        fos.close();
        serverSocket.close();
}

URL编程

URL:统一资源定位符(Uniform Resource Locator) 表示网络上的某一资源的地址

基本结构由五部分组成:

<传输协议>://<主机名>:端口号/文件名?参数列表
http://192.168.1.1:8080/asd/index.html?username=shksd
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shstart7

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值