Java Notes - リフレクション/データベース接続プール/IO ストリーム

リフレクション/データベース接続プール/IOストリーム

1 Java リフレクション メカニズム

  1. 反省とは何ですか?

    リフレクションはクラスの「イントロスペクション」とも呼ばれ、クラス自体の内容 (プロパティ、メソッド、コンストラクターなど) を動的に取得し、クラスのオブジェクトを動的に作成して、これらのプロパティとメソッドを呼び出します

    以前に書いたコードのほとんどはコンパイル時に定義されており、クラス オブジェクトの作成と属性またはメソッドの呼び出しはコンパイル時に正常に作成されています。

    コンパイル中に書かれたコードは汎用的ではないため、より一般的で柔軟なコードを書きたい場合、コンパイラでオブジェクトを作成したり、プロパティやメソッドを呼び出したりすることはできません。

    実行時にクラスのオブジェクトを動的に作成し、オブジェクト内のプロパティとメソッドを動的に呼び出すには、リフレクションを使用する必要があります。

    • リフレクションはコンパイル時のコードではなく .class ファイルで動作します。

    Java実行プロセス: .javaコンパイル>.クラス説明>JVM

Java はオブジェクト指向言語です。Java のすべての要素はオブジェクトです。リフレクションでは、Java クラスのすべての要素がオブジェクトを使用して処理されます。

  • プロパティはオブジェクトです: フィールド
  • メソッドはオブジェクトです: メソッド
  • コンストラクターはオブジェクトです: コンストラクター
  • モディファイアもオブジェクトです: モディファイア
  • void はオブジェクトです: Void

1.1 Java リフレクションの基本的な使用法 - クラス内のオブジェクトの作成と属性の操作

  1. クラスの Class オブジェクトを取得します

    • リフレクションは実行時に機能するため、リフレクションを使用する場合は最初にクラス Class のオブジェクトを取得する必要があります。
    • Java のクラスやインターフェースはコンパイル後に Class オブジェクトを持ちますが、この Class オブジェクトはクラスのバイトコード オブジェクトであると考えることができます。
    • Class オブジェクトは、コンパイルされたすべてのクラスまたはインターフェイスを表します。
    • Java でクラスの Class オブジェクトを取得するには 3 つの方法があります
    1. クラスの「フルパス文字列」を渡す
    Class class1=Class.forName("类完整路径字符串");
    
    1. クラス名で取得
    Class class2=类名.class;
    
    1. クラスのオブジェクト名から取得
    类名 对象名 =new 类名();
    Class class3=对象名.getClass();
    
  2. クラスの Class オブジェクトを通じてクラスのプロパティを取得します。

    /**
     * 1. 获得类的Class对象
     * 2.通过该类的Class对象获得该类的属性
     *    对象名.getFields():获得的属性是访问权限为public的属性(包括static属性)
     *
     *    对象名.getDeclaredFields();可或得该类所有方法(含static)
     * 3.获得类的属性名,修饰符,属性类型
     */
    public class 通过反射操作类的属性 {
          
          
        public static void main(String[] args) {
          
          
            Class userClass= User.class;
    //          通过得类的Class对象获得该类的属性
    //        Field[] userFields   = userClass.getFields();
            Field[] userFields= userClass.getDeclaredFields();
            for (Field field :userFields){
          
          
                System.out.println(field);
                //获得属性名
                String fieldName =field.getName();
                System.out.println(fieldName);
    
                //获得属性类型
                Class type=field.getType();
                System.out.println(type);
    
                //获得属性修饰符
                int modifierNum =field.getModifiers();
                //由于通过getModifiers()获得的是整数形式,我们需要Modifier类这个整数进行解码
                String modifier=Modifier.toString(modifierNum);
                System.out.println(modifier);
                System.out.println("*******************");
            }
        }
    }
    
  3. 属性名で属性を取得し、その属性を呼び出します

    /**
     * 1.或得该类Class对象
     * 2.或得属性名
     * 3.调用该属性
     *
     */
    public class 通过属性名获得属性并调用该属性 {
          
          
        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
          
          
            Class userClass= User.class;
    
            Field username=userClass.getDeclaredField("username");
    
            //反射调用该属性的方法
            //1.创建该类对象
            Object obj= userClass.newInstance();
            /**
             *   2.设置属性值
             *属性名.set(对象名,"属性值")
             */
           username.set(obj,"大王");
            /**
             * 3.调用属性
             */
            Object username1=username.get(obj);
            System.out.println(username1);
    
        }
    }
    

1.2 Java リフレクションの基本的な使用法 - 操作クラスのメソッドとコンストラクター

  1. リフレクションを通じて、またはこのメソッドを取得して呼び出します

    public class 通过反射或得该方法并调用该方法 {
          
          
    
        public static void main(String[] args) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
          
          
            Class<User> userClass= User.class;
    
            //获得方法对象,根据方法名和参数列表
            Method setUserId=userClass.getDeclaredMethod("setUserId", Integer.class);
            //创建类对象
            User user=userClass.newInstance();
            //调用该方法
            /**
             * 反射中调用方法
             * 方法对象名.invoke(类对象名,方法参数列表)
             */
            setUserId.invoke(user,2);
    
            Method getUserId=userClass.getDeclaredMethod("getUserId");
            Object userId=getUserId.invoke(user);
            System.out.println(userId);
    
        }
    }
    
  2. リフレクションを使用してクラス内のコンストラクターを操作する

    public class 通过反射操作类的构造器 {
          
          
        public static void main(String[] args) {
          
          
            Class<User> userClass = User.class;
            //获得类中构造方法
            Constructor[] constructors = userClass.getDeclaredConstructors();
            for (Constructor constructor : constructors) {
          
          
                //修饰符
                int modifiers = constructor.getModifiers();
                String modifier = Modifier.toString(modifiers);
                //参数列表
                Class[] aClass = constructor.getParameterTypes();
                System.out.print("参数列表");
                for (Class object : aClass) {
          
          
                    System.out.print(object+"/");
                }
                //异常
                System.out.println();
                System.out.print("异常列表:");
                Class[] exception = constructor.getExceptionTypes();
                for (Class c:exception){
          
          
                    System.out.print(c+" ");
                }
                //方法名
                String name = constructor.getName();
            }
        }
    }
    
  3. リフレクションを使用してコンストラクターを呼び出す

    public class 获得构造方法并调用 {
          
          
        public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
          
          
            Class<User> userClass=User.class;
            //使用默认构造方法创建对象(JDK11后已过时)
            //  Object o =userClass.newInstance();
            //获得无参构造方法
            Constructor constructor=userClass.getConstructor();
            //使用构造方法创建类的对象
            Object o =constructor.newInstance();
    
            //获得有参数的构造方法
            Constructor constructor1=userClass.getConstructor(Integer.class,String.class,Integer.class);
            Object o1=constructor1.newInstance(1,"张三",1);
    
            System.out.println(o1);
        }
    }
    
    

1.3 反射テスト

  1. エバリュエーター
    リフレクションを使用してエバリュエーターを記述し、エバリュエーターを通じてオブジェクトの関連プロパティに値を割り当てます
    。クラスおよびマップ コレクションのパラメーターを使用してメソッドを定義します。パラメーターの
    説明:
    1. クラス エンティティ クラスのバイトコード オブジェクト
    2. Map コレクションのキー エンティティの属性名、値 属性の値
    戻り値: 属性を設定するオブジェクト

      /**
         * 赋值器创建方法
         * 1.获得属性名和属性值
         * 2.根据属性名拼接set方法
         * 3.调用set方法,并赋值
         *
         * @param clas    类的字节码对象
         * @param map     map集合key是属性名  value是属性值
         * @return
         */
        public static <T> T setter(Class<T> clas, Map<String,Object> map) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
            T t=clas.getDeclaredConstructor().newInstance();
            for (Map.Entry<String,Object> entry : map.entrySet() ){
                //获得属性名
                String fieldName =entry.getKey();
                //获得属性值
                Object fieldValue=entry.getValue();
                //根据属性名拼接set方法
                String methodName ="set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
                //创建属性对象
                Field field=clas.getDeclaredField(fieldName);//主要用来获得该属性对应的参数类型
                //创建方法对象
                Method method=clas.getDeclaredMethod(methodName,field.getType());
                //调用该方法对象
                method.invoke(t, fieldValue);
            }
           return t;
        }
    
  2. リクエストのパラメータ文字のカプセル化をカプセル化し、Javabean オブジェクトを返します。

    • リクエストパラメータを自動的にカプセル化するツールクラスを定義します。クラスには静的メソッドが定義されており、リクエストされたパラメータ文字をJavaBeanオブジェクトにカプセル化してそれを返すために使用されます。パラメータの説明: 1. カプセル化されるクラスのバイトコード
      オブジェクトクラス 2
      による
      .HttpServletRequest リクエスト オブジェクトの
      戻り値: カプセル化されたオブジェクト
      public static <T> T fenzhuangByRequest(Class<T> clas, HttpServletRequest request) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException, ParseException {
          
          
         //获得客户端提交的参数信息,获得一个Map集合key是参数名,value是参数值
         Map<String, String[]> map = request.getParameterMap();
         //获得类字节码对象
         T javabean = clas.getDeclaredConstructor().newInstance();
         for (Map.Entry<String, String[]> entry : map.entrySet()) {
          
          
             //判断是否有值
             if (entry.getValue() == null || entry.getValue().length == 0) {
          
          
                 continue;
             }
             //拼接set方法
             String methodName = "set" + entry.getKey().substring(0, 1).toUpperCase() + entry.getKey().substring(1);
             //获得属性对象和方法对象
             Field field = clas.getDeclaredField(entry.getKey());
             Method method = clas.getDeclaredMethod(methodName, field.getType());
             //调用该方法
             if (field.getType() == String.class) {
          
          
                 method.invoke(javabean, entry.getValue()[0]);
             } else if (field.getType() == Date.class) {
          
          
                 Date date = new SimpleDateFormat("yyyy-MM-dd").parse(entry.getValue()[0]);
                 method.invoke(javabean, date);
             } else if (field.getType() == Integer.class) {
          
          
                 method.invoke(javabean,Integer.parseInt(entry.getValue()[0]));
             }else if (field.getType().isArray()){
          
          
                 method.invoke(javabean, (Object) entry.getValue());
             }
         }
         return javabean;
     }
    
    
  3. BeanUtilsの型コンバータを使用して日付型を処理します。

              /** 方案1:判断属性类型如果是util.Date则进行手动转换
                 */
                if (field.getType() == Date.class) {
          
          
                    Date value1 = new SimpleDateFormat("yyyy-MM-dd").parse(entry.getValue()[0]);
                    method.invoke(t, value1);
                } else {
          
          
                    method.invoke(t, ConvertUtils.convert(entry.getValue(), field.getType()));
                }
                /**
                 * 方案2:向Convert中注册一个类型转换,该类型转换器BeanUtils中提供的转换器
                 *
                 *   向ConvertUtils中注册一个转换器,DteLocaleConverter
                 *   参数1:类型转换器对象
                 *   参数2:转换类型,当需要转换时使用该类型当前注册的类型转换器进行转换
                 */
                ConvertUtils.register(new DateLocaleConverter(Locale.getDefault(), "yyyy-MM-dd"), Date.class);
                /**
                 * 使用自己的转换器,向Convert中注册
                 */
                ConvertUtils.register(new Converter() {
          
          
                    @Override
                    public Object convert(Class aClass, Object o) {
          
          
                        if (entry.getValue()[0] == null) {
          
          
                            return null;
                        }
                        if (!(entry.getValue()[0] instanceof String)) {
          
          
                            throw new ConversionException("只支持字符类转换");
                        }
                           String str=(String) entry.getValue()[0];
                        try {
          
          
                            return new SimpleDateFormat("yyyy-MM-dd").parse(str);
                        } catch (ParseException e) {
          
          
                            throw new RuntimeException(e);
                        }
                    }
                }, Date.class);
    

1.4 リフレクティブカプセル化クエリ機能

    /**
     * 封装查询多行数据功能
     *
     * @param clas
     * @param sql
     * @param params
     * @return
     */
    public List<T> executeQuery(Class<T> clas, String sql, Object... params) {
    
    
        try {
    
    
            getConn();
            ps = conn.prepareStatement(sql);
            if (params != null && params.length != 0) {
    
    
                for (int i = 0; i < params.length; i++) {
    
    
                    ps.setObject(i + 1, params[i]);
                }
            }
            rs = ps.executeQuery();
            List<T> list = new ArrayList<>();
            //获取元数据
            ResultSetMetaData metaData = ps.getMetaData();
            //获取查询列数
            int countNum = metaData.getColumnCount();
            while (rs.next()) {
    
    
                //创建对象
                T t = clas.getDeclaredConstructor().newInstance();
                for (int i = 0; i < countNum; i++) {
    
    

                    //列名与属性名一致
                    String fieldName = metaData.getColumnName(i + 1);
                    //拼接得到set方法
                    String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                    //获得属性对象
                    Field field = clas.getDeclaredField(fieldName);
                    //获得对应方法对象
                    Method method = clas.getDeclaredMethod(methodName, field.getType());
                    //获得一列数据,并将该数据转换为指定的类型
                    Object value = rs.getObject(i + 1, field.getType());
                    method.invoke(t, value);
                }
                list.add(t);
            }
            return list;
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            closeAll();
        }
        return null;
    }

    /**
     * 封装查询单行数据功能
     *
     * @param clas
     * @param sql
     * @param params
     * @param <T>
     * @return
     */
    public <T> T executeQueryOne(Class<T> clas, String sql, Object... params) {
    
    
        try {
    
    
            getConn();
            ps = conn.prepareStatement(sql);
            if (params != null && params.length != 0) {
    
    
                for (int i = 0; i < params.length; i++) {
    
    
                    ps.setObject(i + 1, params[i]);
                }
            }
            rs = ps.executeQuery();
            //获取元数据
            ResultSetMetaData metaData=ps.getMetaData();
            //获取列数
            int countNum = metaData.getColumnCount();
            if (rs.next()){
    
    
//                创建类对象
                T t=clas.getDeclaredConstructor().newInstance();
                for (int i=0;i<countNum;i++){
    
    
                    //获取列名=属性名
                    String fieldName= metaData.getColumnName(i+1);
                    //获取方法名
                    String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                    //获得属性对象
                    Field field = clas.getDeclaredField(fieldName);
                    //获得对应方法对象
                    Method method = clas.getDeclaredMethod(methodName, field.getType());
                    //获取列值
                    Object value =rs.getObject(i+1,field.getType());
                    method.invoke(t,value);
                }
                return t;
            }

        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            closeAll();
        }
        return null;
    }


    /**
     * 通用查询-统计查询
     * @param sql       SQL语句
     * @param params    SQL语句中?号占位符的值
     * @return          存有查询结果的Bean对象
     */
    public Long executeQueryCount(String sql, Object... params){
    
    
        try {
    
    
            //连接数据库
            this.getConn();
            //创建预处理对象
            ps = conn.prepareStatement(sql);
            //判断SQL语句中是否包含?号占位符(params有值表示有?号占位符,有一个值表示有一个?,有多个值表示有多个?)
            if(params!=null && params.length!=0){
    
    
                //循环设置?号占位符的
                for (int i = 0; i < params.length; i++) {
    
    
                    ps.setObject(i+1,params[i]);
                }
            }
            //执行查询语句
            rs = ps.executeQuery();
            if(rs.next()){
    
    
                return Long.valueOf(rs.getInt(1));
            }

        } catch (Exception e) {
    
    
            e.printStackTrace();
        }  finally {
    
    
            closeAll();
        }
        return 0L;
    }

1.5 リフレクションを使用してサーブレットをカプセル化する [単純なユーザー管理プロジェクト]

ソースコードはここにあります。自分で入手する必要があります

ここに画像の説明を挿入

反射の長所と短所

  • リフレクションの利点:

    リフレクションにより、プログラムの柔軟性と拡張性が向上し、結合が減少し、自己適応性が向上します。これにより、プログラムはターゲット クラスを事前にハードコーディングすることなく、任意のクラスのオブジェクトを作成および制御できます。

  • 反射のデメリット

    パフォーマンスの問題。リフレクションの使用は基本的に解釈操作であり、フィールドやメソッドへのアクセスに使用すると、直接コードよりもはるかに遅くなります。したがって、リフレクション メカニズムは主に、高い柔軟性と拡張性が必要なシステム フレームワークで使用され、通常のプログラムには推奨されません。

2 データベース接続プール

従来のデータベース接続は、プログラムを通じてデータベースに接続し、データベース リソースを解放します。

  • 頻繁に接続と解放を行うと、システム リソースが大幅に浪費され、非効率になります。
  • 実際の開発ではリモートデータベースを使用するため、ネットワークの遅延やデータベースの頻繁な接続とシャットダウンが発生し、効率が低下します。

所以我们引入数据库连接池

2.1 データベース接続プールの概念

データベース接続プールはプーリングの考え方に基づいて実装されています

データベース接続プールの基本原則

  1. システム作成時にパーツ(初期化オブジェクト)接続オブジェクトとデータベース接続を自動作成します。

  2. システムにデータベースを操作する機能がある場合、データベースとの接続を確立する必要はありませんが、接続プールからアイドル状態の接続オブジェクトを取得して使用し、接続オブジェクトをビジーとしてマークする必要があります。

  3. データベース操作が完了したら、接続オブジェクトを接続プールから切断し、オブジェクトをアイドルとしてマークします。

  4. 接続プール内の接続オブジェクトが使用要件を満たさない場合、接続プールは自動的にいくつかの接続オブジェクトを作成し、それらを接続プールに入れて使用します。

  5. 接続プールの接続オブジェクトが上限に達すると、新しい接続オブジェクトは作成されなくなります

  6. 接続プール内のすべての接続オブジェクトが占有されている場合、新しい操作は待機キューに置かれ、接続プール内の接続オブジェクトが空になるのを待ちます。

  7. 接続プール内に多数のアイドル状態の接続がある場合、接続プールは一部の接続オブジェクトを解放します。

データベース接続プールはマップ コレクションに基づいて実装されます。

オープンソースのスリーパーティ接続プールが多数あります: C3P0 接続プール、DBCP 接続プール、Druid 接続プール

aibaba の Druid 接続プールを使用します

2.2 Druidベースのデータベース接続プールテクノロジーの実装

構成プロパティ

#配置数据库连接属性
#驱动字符串
druid.driverClassName=com.mysql.cj.jdbc.Driver
#数据库连接url
druid.url=jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false
#数据库账号和密码
druid.username=****
druid.password=****



#配置数据库连接池相关属性
#初始化连接数量
druid.initialSize=5
#最大活动连接
druid.maxActive=100
#最小空闲连接
druid.midIdle=1
#最大等待时间
druid.maxWait=1000
  private static  DruidDataSource dataSource;
    /**
     * 静态代码块,在类加载时被执行,值执行一次
     * 读取db.properties配置文件并初始化数据库连接池
     */
    static {
    
    
        try {
    
    
            /**
             * 1.读取db.properties中的属性文件
             * 2.创建Druid数据库连接池对象
             */
            //获得输出流对象
            InputStream inputStream = DBUntils.class.getClassLoader().getResourceAsStream("db.properties");
            //创建properties对象,用于存储db.properties文件中的数据
            Properties properties = new Properties();
            properties.load(inputStream);
            //创建Druid数据库连接对象
            //DataSource称为数据源,他是数据的提供者
            dataSource =new DruidDataSource();
            dataSource.configFromPropety(properties);

        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }

    /**
     * 获得连接对象
     * @return
     */
   public Connection getConn() {
    
    
       try {
    
    
           conn=dataSource.getConnection();
       } catch (SQLException e) {
    
    
           e.printStackTrace();
       }
       return conn;
   }

2.3 Druid に基づいたデータベース接続プールの構成 [シンプルなユーザー管理プロジェクト]

ソースコードはここにあります。自分で入手する必要があります

3 わたしの流れ

IO ストリーム: 入出力ストリーム (InputOutput)。主にディスク内のファイルを操作するために使用されます。

  • Java の java.io パッケージの下

  • すべての IO ストリーム操作には入力ストリームと出力ストリームが含まれます

    • 入力ストリーム: ファイルの内容を 1 つずつバイトコードに分割し、これらのバイトコードを IO ストリーム パイプラインを通じて特定の順序でプログラムに渡します。
    • 出力ストリーム: プログラムのコンテンツを 1 つずつバイト コードに分割し、特定の順序とルールに従ってディスク ファイルに転送し、これらのバイト コードを特定のファイル コンテンツに組み立てます。
  • IOストリームの関連演算:
    ①ファイルクラス
    ②バイトストリーム
    ③キャラクタストリーム
    ④データストリーム
    ⑤オブジェクトストリーム

3.1 ファイルクラス

File クラスのインスタンスは、ディスク上のファイルまたはフォルダーを表します。

  • File のインスタンスを通じて、ファイルまたはファイルの関連プロパティを取得できます。
  • Flie クラスは、ファイルの関連プロパティの読み取りまたは設定のみが可能ですが、ファイルのコンテンツを操作することはできません。
  • プログラミングでは、一般にファイルをファイルと呼び、フォルダーをディレクトリと呼びます。
  1. Fileクラスのコンストラクター

    File(File parent, String child): 親ファイル(parent)を元に子ファイルオブジェクトを作成

    File(Sring pathname): ファイルパス(通常使用)を元にファイルオブジェクトを作成

    File(String parent, Sting child): 親ファイルのパスと子ファイル名に基づいてファイルオブジェクトを作成します

    File(URL uri): URIアドレスを元にファイルオブジェクトを作成

    • ファイル file = new File(“d:/key.pri”)

      • 注: ファイル パスの区切り文字は、Windows では「/」バックスラッシュまたは「\」ダブルスラッシュで表されます。

        さまざまなオペレーティング システムのニーズを満たすために、File.separatorオペレーティング システムに応じたセパレータの自動生成を使用できます。

  2. Fileクラスの共通メソッド

    (1) file.exists: ファイルオブジェクトで指定されたファイルが存在するか確認します

    (2) file.createNewFile();: 新しいフォルダーを作成します

    (3) file.getName(): ファイル名文字列を取得

    (4) file.getAbsolutePath(): ファイルの絶対パス文字列を取得

    (5) file.getCanonicalPath(): ファイル指定パスの文字列を取得

    ps:<まずfile.getAbsolutePath()絶対パス文字列を取得し、それを正規パス文字列に変換します>

    (6) file.getName().substring(file.getName().lastIndexOf(".")+1): ファイル拡張子を取得する

    (7) file.getTotalSpace(): 配置されているディスクのサイズを取得します (バイト単位: B)

    (8) file.length(): ファイルサイズを取得(バイト単位:B)

    (9) file.lastModified(): 最終変更時刻を取得します(ミリ秒単位)

    (10) file.delete(): ファイルを削除します

    (11) file.deleteOnExit(): JVM の実行中に削除し、削除してシステムを終了します (遅延削除)

    (12) file.isFile(): ファイルかどうかの判定

    (13) file.isDirectory(): ディレクトリかどうかを判定

    (14) file.mkdir(): 第 1 レベルのディレクトリを作成します

    (15) file.mkdirs(): 複数レベルのディレクトリを作成します

    (16) file.getParent(): ファイルの親ディレクトリ名文字列を取得

    (17) file.getParentFile(): ファイルの親ディレクトリのオブジェクトを取得

    (18)file.list()ディレクトリ内のすべてのサブファイルのファイル名文字列を返す

    (19)file.listFiles()ディレクトリ内のすべてのサブファイルの File オブジェクトを取得します

    (20) file.listFiles(FileFilter fileFilter): ファイル フィルタリング インターフェイスを使用して、サブファイル内の指定されたすべてのファイルを取得します

    (21) File.listRoots(): 現在のシステム内のすべてのドライブ文字ファイルを取得し、ファイル配列を返します。

  • 質問 1: 「d:/abc/xyz/hello.java」ディレクトリとファイルを作成するプログラミング

  • 質問 2: 「d:/abc/xyz/hello.java」ディレクトリとファイルを削除するプログラミング

  • 質問 3: ディスク上のすべてのファイルをスキャンします。

    package com.jiazhong.IO.File类;
    import java.io.File;
    /**
     * 扫描指定目录的所有文件
     * 使用递归调用
     */
    public class Demo04 {
          
          
        public static void main(String[] args) {
          
          
            File[] roots = File.listRoots();//获得当前电脑所有磁盘
            for (File file:roots){
          
          
                scannerFile(file);
            }
    
        }
        /**
         * 扫描某个路径所有文件
         * @param file
         */
        static  void scannerFile(File file){
          
          
            if (file==null){
          
          //文件无效,退出本次循环
                return;
            }
            if (file.isFile()){
          
          //如果是文件输出文件地址,退出本次调用
                String filePath=file.getAbsolutePath();
                System.out.println(filePath);
                return;
            }
    
            if (file.isDirectory()){
          
          
                 //获得当前目录所有子文件
                File[] files = file.listFiles();
                if (files!=null&&files.length!=0){
          
          
                    //遍历子文件
                    for (File file1:files){
          
          
                        scannerFile(file1);
                    }
                }
            }
        }
    }
    

3.2 バイト入出力ストリーム (InPutStream/OutPutStream)

バイトストリームは、すべてのストリームの基礎となるバイトコードの形式でデータを送信し、他のストリームはバイトストリームに基づいて動作します。

バイト ストリームは、InPutStream/OutPutStream という 2 つの基本ストリームを提供しますが、これら 2 つのストリームは抽象クラスであり、バイト ストリームの基本クラスです。

バイト入出力ストリームを使用する場合、通常、FileInPutStream と FileOutOutStream という 2 つのストリームを使用して、バイト ストリームに基づいて入出力操作を実装します。

バイト ストリームはテキスト ファイルを操作できますが、バイト ストリームは文字化けしやすく、バイナリ ファイルの操作によく使用されるバイトを操作するため、お勧めできません。

バッファ付きバイト ストリーム、BufferedInputStream と BufferedOutputStream、これら 2 つのストリームにはデフォルトのバッファがあり、読み取り効率を向上させることができます

  • FileInPutStream と FileOutOutStream はノード ストリーム (生のストリーム) です。

  • BufferedInputStream および BufferedOutputStream (処理ストリーム)、元のストリームを処理するための

    • BufferedInputStream と BufferedOutputStream には、8K のサイズのデフォルト バッファーがあります。カスタム バッファーが 8K より大きい場合は、カスタム バッファーを使用します。それ以外の場合は、研削バッファーを使用します。
  • 外側のストリームは閉じられ、内側のストリームは自動的に閉じられます

  1. バイト入力ストリーム
/**
 * 字节输入流实例
 */
public class Demo01 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        InputStream inputStream = new FileInputStream("d:/hello java.txt");
        //读取文件内容
        //读取一个字节
       /* int num=inputStream.read();
        System.out.println((char)num);
        */
        //一次读取多个字节,组装到字节数组中
        byte[] buf = new byte[1024];
        int len = -1;
//        将读取到的字节存入到buf中,返回值实际读到的内容
        while ((len = inputStream.read(buf)) != -1) {
    
    
            String str = new String(buf,0,len);//从下标为0开始到下标为len结束创建字符串
            System.out.println(str);
        }
        inputStream.close();
    }
}
  1. バイト出力ストリーム

    バイト出力ストリームがターゲット ファイルにコンテンツを出力する場合、ターゲット ファイルが存在しない場合はコンテンツを書き込むファイルを作成し、存在する場合はコンテンツを更新します

    更新したくない場合は、FileInputStream オブジェクトの 2 番目のパラメーターを true に指定します。

    OutputStream outputStream=new FileOutputStream("D:/hello.txt",true);
    
    /**
     * 字节输出流
     */
    public class Demo02 {
          
          
        public static void main(String[] args) throws IOException {
          
          
            OutputStream outputStream=new FileOutputStream("D:/hello.txt",true);
            Scanner scanner=new Scanner(System.in);
            System.out.println("请输入要输出的内容,输出N时结束:");
            Boolean flag=false;
            while (!flag){
          
          
                String str=scanner.nextLine();//输出一行数据
                if (str.equals("N")||str.equals("n")){
          
          
                    break;
                }
                //将一个字符串转化为字节数组
                byte[] bytes = str.getBytes();
                outputStream.write(bytes);
                outputStream.write("\n".getBytes());
               outputStream.flush();//刷新流
            }
             outputStream.close();//关闭流
        }
    }
    
    • ファイルコピー
    /**
         * 文件复制
         * @param src  源文件
         * @param desc  目标文件
         * @throws FileNotFoundException
         */ 
    public static void fileCopy(File src,File desc) throws IOException {
          
          
            InputStream inputStream=new FileInputStream(src);
            OutputStream outputStream=new FileOutputStream(desc,true);
    
            byte[] buf = new byte[1024*1024*10];
            int len=-1;
            while ((len=inputStream.read(buf))!=-1){
          
          
                outputStream.write(buf,0,len);
                outputStream.flush();
            }
            inputStream.close();
            outputStream.close();
        }
    

3.3 ファイルのエンコード方式

① ISO-8859-1: 西洋コーディング、西洋言語のインテリジェントな認識

②GBK: 中国語の標準エンコーディング。簡体字と繁体字を認識でき、1 文字は 2 バイトを占有します。

③GB2312: 簡体字中国語の標準エンコーディング、簡体字中国語のインテリジェント認識、1 文字が 2 バイトを占有

④UTF-8:ほぼすべての国の言語を認識できる国際的なエンコーディングであり、1文字は3バイトを占めます。

⑤Unicode:Javaで使用されるエンコード

⑥ANSI:オペレーティングシステムコード、我が国で使用されているWindows OSはGBKまたはGB2312です

  • ファイルを操作する場合、外部ファイルのエンコード方式がJavaで使用されるエンコード(Unicode)と一致していないため、トランスコードが必要となります。

    • 外部ファイルのエンコーディングを Java エンコーディングに変換します。これをデコーディングと呼びます。

      String str=new String(buf,o,len,"GBK")外部ファイルエンコーディング「GBK」をJavaエンコーディングに変換します

    • Java エンコーディングを外部ファイル エンコーディングに変換します。これをエンコーディングと呼びます。

      byte[] buf=str.getBytes("GBK")「Javaエンコーディングを外部エンコーディングに変換」

3.4 ブリッジストリーム(バイトから文字への変換ストリーム)

バイトから文字への変換ストリームは処理ストリームに属します

バイトストリームの最下層は、「バイトストリーム」を通じて元のデータを読み取り、読み取った「バイトデータ」を「文字データ」に変換します。

バイトから文字への変換ストリームは、外部ファイルに従ってエンコードされ、バイト データを文字データに変換し、外部エンコードを指定します。

バイトから文字への変換ストリームは特定の文字ストリームに基づいています

バイトから文字への変換ストリーム: InputStreamReader と OutPutStreamWrite はこれら 2 つのクラスによって実装されます

InputStreamReader: Reader クラスを継承する、バイトから文字への入力ストリームです。

OutPutStreamWrite: バイトから文字への出力ストリームであり、Write クラスを継承します。

リーダー クラス: 抽象クラスであり、文字入力ストリームの基本クラスです。

書き込みクラス: 抽象クラスであり、文字出力ストリームの基本クラスです。

  • バイトから文字への変換ストリームを使用して、外部ファイルのエンコード設定に従ってエンコードを変換します。
  1. バイトから文字への入力ストリーム
/**
 * 字节到字符输入流
 */
public class Demo01 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        InputStream inputStream = new FileInputStream("D:\\hello java.txt");
        //该流会将读到的字节转换为字符,并根据指定的编码进行转换
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"GBK");
        char[] buf = new char[1024];
        int len = -1;
        while ((len = inputStreamReader.read(buf)) != -1) {
    
    
              String str=new String(buf,0,len);
            System.out.println(str);
        }
        inputStream.close();
    }
}
  1. バイトから文字への出力ストリーム
/**
 * 字节到字符输入流
 */
public class Demo01 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        InputStream inputStream = new FileInputStream("D:\\hello java.txt");
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"GBK");

        char[] buf = new char[1024];
        int len = -1;
        while ((len = inputStreamReader.read(buf)) != -1) {
    
    
              String str=new String(buf,0,len);
            System.out.println(str);
        }
        inputStream.close();
    }
}

3.5 文字ストリーム

文字ストリームには、FileReader と FileWrite という 2 つのクラスが含まれており、それぞれ、InputStreamReader と OutputStream の 2 つの変換ソースを継承します。

FileWrite と FileReader は、InputStreamReader と OutputStream の簡潔な実装であり、これら 2 つの文字ストリーム クラスによってエンコーディングが強化され、エンコーディングは一律 UTF-8 を使用します。

  • FileReaderやFileWriterではエンコードの設定はできず、UTF-8エンコードでのみ変換できるため、UTF-8でエンコードされたテキストファイルのみ操作可能です。
    • FileReader および FileWriter は、JDK11 以降に設定されたエンコード設定をサポートします
  • BufferedReader と BufferedWriter の 2 つのクラスは内部にバッファーを持っており、効率が適切に向上しますが、この 2 つのストリームは効率を向上させるためではなく、これら 2 つのクラスで文字データを操作する利便性を向上するために使用されます。
    • BufferedReader と BufferedWriter はパッケージ化ストリームに属しており、Reader と Writer サブクラス オブジェクトのパッケージ化には、FileReader と FileWriter を基本ストリームとして使用するか、
      InputStreamReader と OutputStreamWriter を基本ストリームとして使用できます。
  1. 文字入力ストリーム
/**
 * 字符输入流
 */
public class Demo02 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        Reader reader=new FileReader("d:/hello java.txt");
        char[] buf=new char[1024];
        int len=-1;
        while ((len=reader.read(buf))!=-1){
    
    
            String str=new String(buf,0,len);
            System.out.println(str);
        }
        reader.close();
    }
}
  1. 文字出力ストリーム
public class Demo01 {
    
    
    public static void main(String[] args) throws IOException {
    
    
         Writer writer=new FileWriter("d:/hello.txt");
        writer.write("你好");
        writer.flush();
        writer.close();
    }
}
  1. 文字入力および出力バッファ ストリーム
public class BufferDemo  {
    
    
    public static void main(String[] args) throws IOException {
    
    
//        bufferReader();
        bufferWrite();
    }
    /**
     * 缓冲字符输出流
     * @throws IOException
     */
    private static void bufferWrite() throws IOException {
    
    
        Writer writer=new FileWriter("d:/hello.txt");
        BufferedWriter bufferedWriter=new BufferedWriter(writer);
        Scanner scanner=new Scanner(System.in);
        String str=scanner.nextLine();
        bufferedWriter.write(str);
        bufferedWriter.newLine();//输出一个换行符
        writer.flush();

        writer.close();
    }

    /**
     * 缓冲输入流
     */
     static void bufferReader() throws IOException {
    
    
       /**
        Reader reader=new FileReader("d:/hello java.txt");
        BufferedReader bufferedReader=new BufferedReader(reader);
        */
       //创建字节输入流对象
       InputStream inputStream=new FileInputStream("d:/hello java.txt");
       //创建字节到字符流对象
       InputStreamReader inputStreamReader=new InputStreamReader(inputStream);
       //创建字符缓冲流对象
       BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
        String len=null;
        while ((len=bufferedReader.readLine())!=null){
    
    
            System.out.println(len);
        }
        inputStream.close();
    }
}

3.6 印刷ストリームとデータストリーム

  1. 印刷ストリーム

    Printwriter: ターゲットの場所にテキストを書き込みます

    public class Demo01 {
          
          
        public static void main(String[] args) throws IOException {
          
          
            //控制台输入
    //        Scanner scanner=new Scanner(System.in);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
            bufferedReader.read();
            //控制台输出
            PrintWriter printWriter = new PrintWriter(System.out);
            while (true) {
          
          
                String s = bufferedReader.readLine();
                printWriter.write(s);
                if (s.equals("n")) {
          
          
                    break;
                }
                printWriter.flush();
            }
            bufferedReader.close();
            printWriter.close();
        }
    }
    
  2. データフロー

    このストリームを使用してプリミティブ データ型を入力および出力します。

    データストリームに従って、あらゆる基本データタイプのデータを読み取ることができます

    操作対象のデータ型が占めるバイト数に応じて、データ ストリームは対応するバイト数を一度に読み書きし、基本的なデータ型の操作の精度と効率を実現します。

    データ ストリームは 2 つのクラス (DataInputStream/DataOutPutStream) で構成されます。

    public class Demo01 {
          
          
        public static void main(String[] args) throws IOException {
          
          
            dataOutputStream();
            dataInputStream();
        }
        /**
         * 数据输出流
         * @throws IOException
         */
        private static void dataOutputStream() throws IOException {
          
          
            DataOutputStream dataOutputStream=new DataOutputStream(new FileOutputStream("D:/hello.num"));
            dataOutputStream.writeInt(256);
            dataOutputStream.writeInt(5256);
            dataOutputStream.writeInt(2256);
            dataOutputStream.writeInt(2526);
            dataOutputStream.writeDouble(2562.06);
            dataOutputStream.flush();
            dataOutputStream.close();
        }
        /**
         * 数据输入流
         * @throws IOException
         */
        public static void dataInputStream() throws IOException {
          
          
            DataInputStream dataInputStream=new DataInputStream(new FileInputStream("d:/hello.num"));
            try {
          
          
                while (true){
          
          
                    int num = dataInputStream.readInt();
                    System.out.println(num);
                }
            }catch (EOFException e){
          
          
                System.out.println("文件读取结束");
            } dataInputStream.close();
        }
    }
    

3.7 オブジェクトストリーム/シリアル化と逆シリアル化

オブジェクト ストリームは主に、Java オブジェクトの操作、Java オブジェクトのファイルへの書き込み、またはファイルからの Java オブジェクトの読み取りに使用されます。

Java オブジェクトをディスクまたはネットワークに書き込むことをシリアル化といいます。

ファイルまたはネットワーク内のデータを Java オブジェクトに変換することを逆シリアル化といいます。

シリアライズ: Java オブジェクトをバイトコード (ストリーミング) に変換するプロセス
デシリアライズ: バイトコードを Java オブジェクトに変換するプロセス

ObjectInputStream: オブジェクト入力ストリーム/ObjectOutputStream オブジェクト出力ストリーム
ObjectOutputStream: オブジェクトのシリアル化を実現
ObjectInputStream: オブジェクトの逆シリアル化を実現

Java では、インターフェイス (Serializable) を実装するオブジェクトのみがシリアル化および逆シリアル化できると規定されています。

識別インターフェイス(識別に使用される)であるシリアル化可能インターフェイス(Serializable)には、プロパティとメソッドが定義されていません。

Java オブジェクトをシリアル化するとき、JVM はオブジェクトが属するクラスが Serializable インターフェイスを実装しているかどうかを検出します。そうでない場合、JVM はオブジェクトのシリアル化を防ぎます。逆に、オブジェクトが Serializable インターフェイスを実装している場合は、
シリアル化を許可する

  • コレクション クラス オブジェクト。シリアル化したい場合は、内部の要素も Serializable インターフェイスを実装する必要があります。

  • シリアル化されたオブジェクトが別のクラスの属性を持っている場合、その属性をシリアル化する場合は、対応するクラスも Serializable インターフェイスを実装する必要があります。

  • プロパティをシリアル化できない場合、プロパティを trainient で変更します。つまり、プロパティはシリアル化できません。つまり、trainient でマークされたプロパティは、シリアル化中にシリアル化されないように特別に処理されます。注: 静的プロパティは、trainient によって変更されたかどうかに関係なくシリアル化できません。

package com.jiazhong.IO.对象流;
import com.jiazhong.IO.对象流.model.User;
import java.io.*;
public class ObjectStream {
    
    
    public static void main(String[] args) throws IOException, ClassNotFoundException {
    
    
//        ObjOutputStream();
        ObjInputStream();
    }

    /**
     * 将Java对象存储到磁盘中
     *
     * @throws IOException
     */
    public static void ObjOutputStream() throws IOException {
    
    
        User user = new User(2, "校长", "123456");
        User user1 = new User(1, "校长", "123456");
        User user2 = new User(3, "校答长", "123456");
        User user3 = new User(5, "校按时长", "123456");
        User user4 = new User(4, "校达个长", "123456");
        User user5=new User(6,"dasd","123456","男");
        //创建对象输出流对象
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:/user.obj"));
        objectOutputStream.writeObject(user);
        objectOutputStream.writeObject(user1);
        objectOutputStream.writeObject(user2);
        objectOutputStream.writeObject(user3);
        objectOutputStream.writeObject(user4);
        objectOutputStream.writeObject(user5);
        objectOutputStream.flush();
        objectOutputStream.close();
    }
    /**
     * 从磁盘中读取数据并转化为Java对象
     */
    public static void ObjInputStream() throws IOException, ClassNotFoundException {
    
    
        //创建对象输入流对象
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:/user.obj"));
        try {
    
    
            while (true) {
    
    
                User user = (User) objectInputStream.readObject();
                System.out.println(user);
            }
        } catch (IOException e) {
    
    
            System.out.println("已读完");
            e.printStackTrace();
        }
        objectInputStream.close();
    }
}

  • 学びは西安家中の訓練から生まれる

おすすめ

転載: blog.csdn.net/woschengxuyuan/article/details/129160665