分类 Code 下的文章

这个问题一般是 release 版本的时候才会出现,解决这个问题的办法其实报错的提示里面已经说了:

android {
    lintOptions {
        checkReleaseBuilds false
        // Or, if you prefer, you can continue to check for errors in release builds,
        // but continue the build even when errors are found:
        abortOnError false
    }
}

就是在 build.gradle 里面的 android 条目下面增加 lintOptions 即可 release 成功。

参考:

android/flutter 打包报错 ':app:lintVitalRelease'
https://zhuanlan.zhihu.com/p/80453995

把程序文件下的数据库文件复制到其他目录,需要用到文件复制。

/**
 * @author ptz
 * @date 2022/02/05
 * @description
 */
public class CopyFile {
    private static final String TAG = "CopyFile";
    /**
     * 根据文件路径拷贝文件
     * @param srcPath 源文件
     * @param destDir 目标文件路径
     * @param fileName 目标文件名
     * @return boolean 成功true、失败false
     */
    public static boolean copyFile(String srcPath, String destDir, String fileName) {
        boolean result = false;

        DLog.w(TAG, "copyFile: src: " + srcPath + ", dest: " + destDir + fileName);

        File src = new File(srcPath);
        if ((src == null) || (destDir== null)) {
            return false;
        }

        File dir = new File(destDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        File dest= new File(destDir + fileName);
        if (dest!= null && dest.exists()) {
            boolean ret = dest.delete(); // delete file
            DLog.d(TAG, "copyFile: delete dest result: " + ret);
        }

        try {
            boolean ret = dest.createNewFile();
            DLog.d(TAG, "copyFile: create dest result: " + ret);
        } catch (IOException e) {
            //e.printStackTrace();
            DLog.d(TAG, Log.getStackTraceString(e));
        }

        FileChannel srcChannel = null;
        FileChannel dstChannel = null;

        try {
            srcChannel = new FileInputStream(src).getChannel();
            dstChannel = new FileOutputStream(dest).getChannel();
            srcChannel.transferTo(0, srcChannel.size(), dstChannel);
            result = true;
        } catch (FileNotFoundException e) {
            //e.printStackTrace();
            DLog.d(TAG, Log.getStackTraceString(e));
        } catch (IOException e) {
            //e.printStackTrace();
            DLog.d(TAG, Log.getStackTraceString(e));
        }

        try {
            srcChannel.close();
            dstChannel.close();
        } catch (Exception e) {
            //e.printStackTrace();
            DLog.d(TAG, Log.getStackTraceString(e));
        }

        return result;
    }
}
/**
 * @author ptz
 * @date 2022/02/05
 * @description
 */
public class FileName {
    /**
     * 仅保留文件名不保留后缀
     */
    public static String getFileName(String path) {
        int start = path.lastIndexOf("/");
        int end = path.lastIndexOf(".");
        if (start != -1 && end != -1) {
            return path.substring(start + 1, end);
        } else {
            return null;
        }
    }

    /**
     * 保留文件名及后缀
     */
    public static String getFileNameWithSuffix(String path) {
        int start = path.lastIndexOf("/");
        if (start != -1 ) {
            return path.substring(start + 1);
        } else {
            return null;
        }
    }

    /**
     * 仅保留目录名
     */
    public static String getDirName(String path) {
        int start = 0;
        int end = path.lastIndexOf("/");
        if (start != end && end != -1) {
            return path.substring(start, end + 1);
        } else {
            return null;
        }
    }
}

参考

可能是最完美的Android复制拷贝文件的实例(Java NIO速度快)
https://blog.csdn.net/mvpstevenlin/article/details/54090722
java如何操作字符串取得绝对路径中的文件名及文件夹名
https://blog.csdn.net/weiqiang_1989/article/details/50987852

转自: https://blog.csdn.net/cf8833/article/details/92662279

遇到的坑:

  1. 这个东西只能保存崩溃的错误日志,有点局限性
  2. 文件权限申请,文件权限申请,文件权限申请,重要的事情讲三遍,
  3. 这个生成之后的文件,一定要用手机去看,千万不要用电脑,别问题为什么,因为电脑看的那个文件夹没刷新,不显示,还有我们存储路径的wangrusheg 这个东西是可变化的,是你的项目名称,千万不要傻愣愣的一直去找这个文件夹 这个是项目名称,项目名称,项目名称!!!!切记

先看效果图:

1.权限,文件的读写,在清单文件里面,注意,我这里为了方便,没做动态权限申请,你们使用的时候,记得把权限开起来,还有,我们的用到了application,记得在清单文件添加

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.administrator.testz">

        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

        <application
            android:name=".App"
            android:allowBackup="true"
            android:icon="@mipmap/icona"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />

                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>

        </application>

    </manifest>

2.创建App文件

    public class App extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
            CrashHandler crashHandler = CrashHandler.getInstance();
            crashHandler.init(getApplicationContext());
        }
    }

3.MainActivity ,只要是模拟一下报错,你们也可以模拟别的错误,界面我就不贴了,就一个button,自己添加

    package com.example.administrator.testz;

    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;

    import java.util.ArrayList;
    import java.util.List;

    public class MainActivity extends AppCompatActivity {
        private static final String TAG = "MainActivity";

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            final Button button2 = (Button) findViewById(R.id.bug);

            button2.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    List<String> list = new ArrayList<>();

                    String[] strings = CrashHandler.getCrashReportFiles(MainActivity.this);//获取异常文件路径
                    for (int i = 0; i < strings.length; i++) {
                        Log.e(TAG, "onCreate: " + strings[i]);
                    }

                    Log.e(TAG, "onCreate: " + list.get(1));//模拟数组越界
                }
            });

        }
    }

4.日志类

    package com.example.administrator.testz;

    import android.util.Log;

    /**
     * @author DeMon
     * @date 2018/8/14
     * @description
     */
    public class DLog {
        /*m默认不打印Log,如果要打印,置为true*/
        private static boolean enableLog = BuildConfig.DEBUG;

        public static void e(String tag, String msg) {
            if (enableLog)
                Log.e(tag, msg);

        }

        public static void d(String tag, String msg) {
            if (enableLog)
                Log.d(tag, msg);

        }

        public static void i(String tag, String msg) {
            if (enableLog)
                Log.i(tag, msg);

        }

        public static void v(String tag, String msg) {
            if (enableLog)
                Log.v(tag, msg);

        }

        public static void w(String tag, String msg) {
            if (enableLog)
                Log.w(tag, msg);

        }

    }

5.日志写入错误信息类

    package com.example.administrator.testz;

    import android.annotation.SuppressLint;
    import android.content.Context;
    import android.os.Build;
    import android.os.Environment;
    import android.util.Log;

    import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.io.StringWriter;
    import java.io.Writer;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Locale;

    /**
     * @author DeMon
     * @date 2018/8/14
     * @description
     */
    public class CrashHandler implements Thread.UncaughtExceptionHandler {

        private static final String TAG = "CrashHandler";
        /**
         * 系统默认的UncaughtException处理类
         */
        private Thread.UncaughtExceptionHandler mDefaultHandler;
        /**
         * 程序的Context对象
         */
        private Context mContext;
        /**
         * 错误报告文件的扩展名
         */
        private static final String CRASH_REPORTER_EXTENSION = ".txt";

        /**
         * CrashHandler实例
         */
        private static CrashHandler INSTANCE;

        /**
         * 保证只有一个CrashHandler实例
         */
        private CrashHandler() {
        }

        /**
         * 获取CrashHandler实例 ,单例模式
         */
        public static CrashHandler getInstance() {
            if (INSTANCE == null) {
                synchronized (CrashHandler.class) {
                    if (INSTANCE == null) {
                        INSTANCE = new CrashHandler();
                    }
                }
            }
            return INSTANCE;
        }

        /**
         * 初始化,注册Context对象,
         * 获取系统默认的UncaughtException处理器,
         * 设置该CrashHandler为程序的默认处理器
         *
         * @param ctx
         */
        public void init(Context ctx) {
            mContext = ctx;
            mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
            Thread.setDefaultUncaughtExceptionHandler(this);
        }

        /**
         * 当UncaughtException发生时会转入该函数来处理
         */
        @Override
        public void uncaughtException(Thread thread, Throwable ex) {
            handleException(ex);
            if (mDefaultHandler != null) {
                //收集完信息后,交给系统自己处理崩溃
                mDefaultHandler.uncaughtException(thread, ex);
            }
        }

        /**
         * 自定义错误处理,收集错误信息
         * 发送错误报告等操作均在此完成.
         * 开发者可以根据自己的情况来自定义异常处理逻辑
         */
        private void handleException(Throwable ex) {
            if (ex == null) {
                Log.w(TAG, "handleException--- ex==null");
                return;
            }
            String msg = ex.getLocalizedMessage();
            if (msg == null) {
                return;
            }
            //收集设备信息
            //保存错误报告文件
            saveCrashInfoToFile(ex);
        }

        /**
         * 获取错误报告文件路径
         *
         * @param ctx
         * @return
         */
        public static String[] getCrashReportFiles(Context ctx) {
            File filesDir = new File(getCrashFilePath(ctx));
            String[] fileNames = filesDir.list();
            int length = fileNames.length;
            String[] filePaths = new String[length];
            for (int i = 0; i < length; i++) {
                filePaths[i] = getCrashFilePath(ctx) + fileNames[i];
            }
            return filePaths;
        }

        /**
         * 保存错误信息到文件中
         *
         * @param ex
         * @return
         */
        private void saveCrashInfoToFile(Throwable ex) {
            Writer info = new StringWriter();
            PrintWriter printWriter = new PrintWriter(info);
            ex.printStackTrace(printWriter);
            Throwable cause = ex.getCause();
            while (cause != null) {
                cause.printStackTrace(printWriter);
                cause = cause.getCause();
            }
            String result = info.toString();
            printWriter.close();
            StringBuilder sb = new StringBuilder();
            @SuppressLint("SimpleDateFormat") SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
            String now = sdf.format(new Date());
            sb.append("TIME:").append(now);//崩溃时间
            //程序信息
            sb.append("\nAPPLICATION_ID:").append(BuildConfig.APPLICATION_ID);//软件APPLICATION_ID
            sb.append("\nVERSION_CODE:").append(BuildConfig.VERSION_CODE);//软件版本号
            sb.append("\nVERSION_NAME:").append(BuildConfig.VERSION_NAME);//VERSION_NAME
            sb.append("\nBUILD_TYPE:").append(BuildConfig.BUILD_TYPE);//是否是DEBUG版本
            //设备信息
            sb.append("\nMODEL:").append(android.os.Build.MODEL);
            sb.append("\nRELEASE:").append(Build.VERSION.RELEASE);
            sb.append("\nSDK:").append(Build.VERSION.SDK_INT);
            sb.append("\nEXCEPTION:").append(ex.getLocalizedMessage());
            sb.append("\nSTACK_TRACE:").append(result);
            try {
                FileWriter writer = new FileWriter(getCrashFilePath(mContext) + now + CRASH_REPORTER_EXTENSION);
                writer.write(sb.toString());
                writer.flush();
                writer.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        /**
         * 获取文件夹路径
         *
         * @param context
         * @return
         */
        private static String getCrashFilePath(Context context) {
            String path = null;
            try {
                path = Environment.getExternalStorageDirectory().getCanonicalPath() + "/"
                        + context.getResources().getString(R.string.app_name) + "/Crash/";
                File file = new File(path);
                if (!file.exists()) {
                    file.mkdirs();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            Log.e(TAG, "getCrashFilePath: " + path);
            return path;
        }
    }

sqlite 数据库设计超过容量就删除最前面的 n 行数据,用到的 sql 语句如下:

    public void deleteTableHead(SQLiteDatabase db,
                                String table, String column, long num) {
        String delete = "delete from " + table + " where " + column +
                " in(select " + column + " from " + table + " limit " + num + ")";
        db.execSQL(delete);
    }

参考:

删除SQLITE数据库前N行或指定行问题
https://www.cnblogs.com/elect-fans/archive/2012/08/04/2622480.html
Sqlite数据库添加,删除前n条记录
https://blog.csdn.net/asdssaaaa/article/details/52229546
安卓 SQLite 数据库删除前 n 条记录
https://blog.csdn.net/fzhhsa/article/details/103032844?spm=1001.2101.3001.6650.8&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-8.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-8.pc_relevant_default&utm_relevant_index=12
Sqlite之删除超过50条的数据
https://blog.csdn.net/u014213012/article/details/76269768

sg 滤波器: Savitsky Golay filter

github 上面可用的库有两个:

资料

使用问题

  • savitzky-golay-filter 这个需要配套的是 math v2.2
  • jDSP 需要需改 gradle 文件,否则会报错。

参考:

Savitsky-Golay滤波器及源码实现
https://blog.csdn.net/lovelyaiq/article/details/88681499
Savitzky-Golay 滤波器
https://blog.csdn.net/liyuanbhu/article/details/9094945

需要重复字符串 n 次,如果 java 版本高,可以直接使用 String.repeat()

        String str = "Abc";
        System.out.println( str.repeat(3) );

如果版本低,那就使用 regex

        String str = "Abc";
        String repeated = new String(new char[3]).replace("\0", str);
        System.out.println(repeated);

可以直接创建一个重复字符串的函数:

    private String repeatString(String str, int times) {
        return new String(new char[times]).replace("\0", str);
    }

参考:

https://www.learnfk.com/article-java11-repeat-string-n-times

添加 maven { url "https://jitpack.io" }

  • 旧版本在 project 的 build.gradle 中增加:
    allprojects {
    repositories {
        jcenter()
        maven { url "https://jitpack.io" }
    }
    }
  • 新版本在 project 的 settings.gradle 中增加:
    dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url "https://jitpack.io" }
        jcenter() // Warning: this repository is going to shut down soon
    }
    }

添加 implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3'

在 app 中的 build.gradle 中增加: implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0-alpha'

在 xml 中增加:

<com.github.mikephil.charting.charts.LineChart
    android:id="@+id/mvDetailLineChart"
    android:layout_width="match_parent"
    android:layout_height="@dimen/dp200"/>

参考:

https://blog.csdn.net/briblue/article/details/77305697
https://blog.csdn.net/jinmie0193/article/details/90239935
https://www.cnblogs.com/leshen/p/12606161.html
MPAndroidChart个人使用总结(一)
https://www.jianshu.com/p/9746e2dd2fbe
MPAndroid 中文文档(转)
https://www.jianshu.com/p/fc31df1e8679
笑谈Android图表-MPAndroidChart
https://www.imooc.com/article/71442

转自: https://www.cnblogs.com/wangshuo1/p/5697746.html

常常在网上看到有人询问:如何把 java 程序编译成 .exe 文件。通常回答只有两种,一种是制作一个可执行的 JAR 文件包,然后就可以像.chm 文档一样双击运行了;而另一种是使用 JET 来进行 编译。但是 JET 是要用钱买的,而且据说 JET 也不是能把所有的 Java 程序都编译成执行文件,性能也要打些折扣。所以,使用制作可执行 JAR 文件包的方法就是最佳选择了,何况它还能保持Java 的跨平台特性。

下面就来看看什么是 JAR 文件包吧:

1. JAR 文件包

JAR 文件就是 Java Archive File,顾名思意,它的应用是与 Java 息息相关的,是 Java 的一种文档格式。JAR 文件非常类似 ZIP 文件--准确的说,它就是 ZIP 文件,所以叫它文件包。JAR 文件与 ZIP 文件唯一的区别就是在 JAR 文件的内容中,包含了一个 META-INF/MANIFEST.MF 文件,这个文件是在生成 JAR 文件的时候自动创建的。举个例子,如果我们具有如下目录结构的一些文件:

==

`-- test

  `-- Test.class

把它压缩成 ZIP 文件 test.zip,则这个 ZIP 文件的内部目录结构为:

test.zip

`-- test

  `-- Test.class

如果我们使用 JDK 的 jar 命令把它打成 JAR 文件包 test.jar,则这个 JAR 文件的内部目录结构为:

test.jar

|-- META-INF

|  `-- MANIFEST.MF

`-- test

`--Test.class

2. 创建可执行的 JAR 文件包

制作一个可执行的 JAR 文件包来发布你的程序是 JAR 文件包最典型的用法。

Java 程序是由若干个 .class 文件组成的。这些 .class 文件必须根据它们所属的包不同而分级分目录存放;运行前需要把所有用到的包的根目录指定给 CLASSPATH 环境变量或者 java 命令的 -cp 参数;运行时还要到控制台下去使用 java 命令来运行,如果需要直接双击运行必须写 Windows 的批处理文件 (.bat) 或者 Linux 的 Shell 程序。因此,许多人说,Java 是一种方便开发者苦了用户的程序设计语言。

其实不然,如果开发者能够制作一个可执行的 JAR 文件包交给用户,那么用户使用起来就方便了。在 Windows 下安装 JRE (Java Runtime Environment) 的时候,安装文件会将 .jar 文件映射给 javaw.exe 打开。那么,对于一个可执行的 JAR 文件包,用户只需要双击它就可以运行程序了,和阅读 .chm 文档一样方便 (.chm 文档默认是由 hh.exe 打开的)。那么,现在的关键,就是如何来创建这个可执行的 JAR 文件包。

创建可执行的 JAR 文件包,需要使用带 cvfm 参数的 jar 命令,同样以上述 test 目录为例,命令如下:

jar cvfm test.jar manifest.mf test

这里 test.jar 和 manifest.mf 两个文件,分别是对应的参数 f 和 m,其重头戏在 manifest.mf。因为要创建可执行的 JAR 文件包,光靠指定一个 manifest.mf 文件是不够的,因为 MANIFEST 是 JAR 文件包的特征,可执行的 JAR 文件包和不可执行的 JAR 文件包都包含 MANIFEST。关键在于可执行 JAR 文件包的 MANIFEST,其内容包含了 Main-Class 一项。这在 MANIFEST 中书写格式如下:

Main-Class: 可执行主类全名(包含包名)

例如,假设上例中的 Test.class 是属于 test 包的,而且是可执行的类 (定义了 public static void main(String[]) 方法),那么这个 manifest.mf 可以编辑如下:

Main-Class: test.Test <回车>

这个 manifest.mf 可以放在任何位置,也可以是其它的文件名,只需要有 Main-Class: test.Test 一行,且该行以一个回车符结束即可。创建了 manifest.mf 文件之后,我们的目录结构变为:

==

|-- test

|  `-- Test.class

`-- manifest.mf

这时候,需要到 test 目录的上级目录中去使用 jar 命令来创建 JAR 文件包。也就是在目录树中使用“==”表示的那个目录中,使用如下命令:

jar cvfm test.jar manifest.mf test

之后在“==”目录中创建了 test.jar,这个 test.jar 就是执行的 JAR 文件包。运行时只需要使用 java -jar test.jar 命令即可。

需要注意的是,创建的 JAR 文件包中需要包含完整的、与 Java 程序的包结构对应的目录结构,就像上例一样。而 Main-Class 指定的类,也必须是完整的、包含包路径的类名,如上例的 test.Test;而且在没有打成 JAR 文件包之前可以使用 java <类名> 来运行这个类,即在上例中 java test.Test 是可以正确运行的 (当然要在 CLASSPATH 正确的情况下)。

3. jar 命令详解

jar 是随 JDK 安装的,在 JDK 安装目录下的 bin 目录中,Windows 下文件名为 jar.exe,Linux 下文件名为 jar。它的运行需要用到 JDK 安装目录下 lib 目录中的 tools.jar 文件。不过我们除了安装 JDK 什么也不需要做,因为 SUN 已经帮我们做好了。我们甚至不需要将 tools.jar 放到 CLASSPATH 中。

使用不带任何的 jar 命令我们可以看到 jar 命令的用法如下:

jar {ctxu}[vfm0M] [jar-文件] [manifest-文件] [-C 目录] 文件名 ...

其中 {ctxu} 是 jar 命令的子命令,每次 jar 命令只能包含 ctxu 中的一个,它们分别表示:

 -c 创建新的 JAR 文件包

 -t 列出 JAR 文件包的内容列表

 -x 展开 JAR 文件包的指定文件或者所有文件

 -u 更新已存在的 JAR 文件包 (添加文件到 JAR 文件包中)

 [vfm0M] 中的选项可以任选,也可以不选,它们是 jar 命令的选项参数

 -v 生成详细报告并打印到标准输出

 -f 指定 JAR 文件名,通常这个参数是必须的

 -m 指定需要包含的 MANIFEST 清单文件

 -0 只存储,不压缩,这样产生的 JAR 文件包会比不用该参数产生的体积大,但速度更快

 -M 不产生所有项的清单(MANIFEST〕文件,此参数会忽略 -m 参数

 [jar-文件] 即需要生成、查看、更新或者解开的 JAR 文件包,它是 -f 参数的附属参数

 [manifest-文件] 即 MANIFEST 清单文件,它是 -m 参数的附属参数

 [-C 目录] 表示转到指定目录下去执行这个 jar 命令的操作。它相当于先使用 cd 命令转该目录下再执行不带 -C 参数的 jar 命令,它只能在创建和更新 JAR 文件包的时候可用。

文件名 ... 指定一个文件/目录列表,这些文件/目录就是要添加到 JAR 文件包中的文件/目录。如果指定了目录,那么 jar 命令打包的时候会自动把该目录中的所有文件和子目录打入包中。

下面举一些例子来说明 jar 命令的用法:

  1. jar cf test.jar test

该命令没有执行过程的显示,执行结果是在当前目录生成了 test.jar 文件。如果当前目录已经存在 test.jar,那么该文件将被覆盖。

  1. jar cvf test.jar test

该命令与上例中的结果相同,但是由于 v 参数的作用,显示出了打包过程,如下:

标明清单(manifest)

增加:test/(读入= 0) (写出= 0)(存储了 0%)

增加:test/Test.class(读入= 7) (写出= 6)(压缩了 14%)

  1. jar cvfM test.jar test

该命令与 2) 结果类似,但在生成的 test.jar 中没有包含 META-INF/MANIFEST 文件,打包过程的信息也略有差别:

增加:test/(读入= 0) (写出= 0)(存储了 0%)

增加:test/Test.class(读入= 7) (写出= 6)(压缩了 14%)

  1. jar cvfm test.jar manifest.mf test

运行结果与 2) 相似,显示信息也相同,只是生成 JAR 包中的 META-INF/MANIFEST 内容不同,是包含了 manifest.mf 的内容

  1. jar tf test.jar

在 test.jar 已经存在的情况下,可以查看 test.jar 中的内容,如对于 2) 和 3) 生成的 test.jar 分别应该此命令,结果如下;

对于 2)

META-INF/

META-INF/MANIFEST.MF

test/

test/Test.class

对于 3)

test/

test/Test.class
  1. jar tvf test.jar

除显示 5) 中显示的内容外,还包括包内文件的详细信息,如:

0 Wed Jun 19 15:39:06 GMT 2002 META-INF/

86 Wed Jun 19 15:39:06 GMT 2002 META-INF/MANIFEST.MF

0 Wed Jun 19 15:33:04 GMT 2002 test/

7 Wed Jun 19 15:33:04 GMT 2002 test/Test.class
  1. jar xf test.jar

解开 test.jar 到当前目录,不显示任何信息,对于 2) 生成的 test.jar,解开后的目录结构如下:

==

|-- META-INF

|  `-- MANIFEST

`-- test

`--Test.class

jar xvf test.jar

运行结果与 7) 相同,对于解压过程有详细信息显示,如:

创建:META-INF/

展开:META-INF/MANIFEST.MF

创建:test/

展开:test/Test.class

  1. jar uf test.jar manifest.mf

在 test.jar 中添加了文件 manifest.mf,此使用 jar tf 来查看 test.jar 可以发现 test.jar 中比原来多了一个 manifest。这里顺便提一下,如果使用 -m 参数并指定 manifest.mf 文件,那么 manifest.mf 是作为清单文件 MANIFEST 来使用的,它的内容会被添加到 MANIFEST 中;但是,如果作为一般文件添加到 JAR 文件包中,它跟一般文件无异。

  1. jar uvf test.jar manifest.mf

与 9) 结果相同,同时有详细信息显示,如:

增加:manifest.mf(读入= 17) (写出= 19)(压缩了 -11%)

4. 关于 JAR 文件包的一些技巧

  1. 使用 unzip 来解压 JAR 文件

在介绍 JAR 文件的时候就已经说过了,JAR 文件实际上就是 ZIP 文件,所以可以使用常见的一些解压 ZIP 文件的工具来解压 JAR 文件,如 Windows 下的 WinZip、WinRAR 等和 Linux 下的 unzip 等。使用 WinZip 和 WinRAR 等来解压是因为它们解压比较直观,方便。而使用 unzip,则是因为它解压时可以使用 -d 参数指定目标目录。

在解压一个 JAR 文件的时候是不能使用 jar 的 -C 参数来指定解压的目标的,因为 -C 参数只在创建或者更新包的时候可用。那么需要将文件解压到某个指定目录下的时候就需要先将这具 JAR 文件拷贝到目标目录下,再进行解压,比较麻烦。如果使用 unzip,就不需要这么麻烦了,只需要指定一个 -d 参数即可。如:

unzip test.jar -d dest/
  1. 使用 WinZip 或者 WinRAR 等工具创建 JAR 文件

上面提到 JAR 文件就是包含了 META-INF/MANIFEST 的 ZIP 文件,所以,只需要使用 WinZip、WinRAR 等工具创建所需要 ZIP 压缩包,再往这个 ZIP 压缩包中添加一个包含 MANIFEST 文件的 META-INF 目录即可。对于使用 jar 命令的 -m 参数指定清单文件的情况,只需要将这个 MANIFEST 按需要修改即可。

  1. 使用 jar 命令创建 ZIP 文件

有些 Linux 下提供了 unzip 命令,但没有 zip 命令,所以需要可以对 ZIP 文件进行解压,即不能创建 ZIP 文件。如要创建一个 ZIP 文件,使用带 -M 参数的 jar 命令即可,因为 -M 参数表示制作 JAR 包的时候不添加 MANIFEST 清单,那么只需要在指定目标 JAR 文件的地方将 .jar 扩展名改为 .zip 扩展名,创建的就是一个不折不扣的 ZIP 文件了,如将上一节的第 3) 个例子略作改动:

jar cvfM test.zip test

  使用jar命令解决解压缩后,文件乱码问题。

使用JAR解压,命令行下执行 jar -xvf 压缩包.zip

转自: https://blog.csdn.net/byhook/article/details/84037338

音视频实践学习

android全平台编译ffmpeg以及x264与fdk-aac实践
ubuntu下使用nginx和nginx-rtmp-module配置直播推流服务器
android全平台编译ffmpeg合并为单个库实践
android-studio使用cmake编译ffmpeg实践
android全平台编译ffmpeg视频解码器实践
android全平台编译ffmpeg支持命令行实践
android全平台编译ffmpeg视频推流实践
android平台下音频编码之编译LAME库转码PCM为MP3
图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别
ubuntu平台下编译vlc-android视频播放器实践

概述

YUV模型是根据一个亮度(Y分量)和两个色度(UV分量)来定义颜色空间,常见的YUV格式有YUY2、YUYV、YVYU、UYVY、AYUV、Y41P、Y411、Y211、IF09、IYUV、YV12、YVU9、YUV411、YUV420等,其中比较常见的YUV420分为两种:YUV420P和YUV420SP。

我们在android平台下使用相机默认图像格式是NV21属于YUV420SP格式

- 阅读剩余部分 -

转自: https://www.cnblogs.com/tid-think/p/10616789.html#:~:text=%E6%8E%A5%E4%B8%8B%E6%9D%A5%E6%98%AFYUV420,%E6%AF%8F%E5%9B%9B%E4%B8%AAy%E5%88%86%E9%87%8F%E5%85%AC%E7%94%A8%E4%B8%80%E4%B8%AAUV%E5%88%86%E9%87%8F%EF%BC%8C%E6%89%80%E4%BB%A5%E6%AF%8F%E4%B8%AA%E5%83%8F%E7%B4%A0%E7%82%B9%E5%8D%A0%E7%94%A81.5%E4%B8%AA%E5%AD%97%E8%8A%82%E7%A9%BA%E9%97%B4%EF%BC%8C%E6%A0%B9%E6%8D%AE%E5%AD%98%E5%82%A8%E9%A1%BA%E5%BA%8F%E4%B8%8D%E4%B8%80%E6%A0%B7%E5%8F%88%E5%88%86%E4%B8%BA%E5%9B%9B%E4%B8%AA%E4%B8%8D%E5%90%8C%E7%9A%84%E7%B1%BB%E5%9E%8B%E3%80%82

前段时间搞x264编码测试,传参的时候需要告诉编码器我的原始数据格式是什么,其中在x264.h头文件中定义了如下一堆类型。

/* Colorspace type */
#define X264_CSP_MASK           0x00ff  /* */
#define X264_CSP_NONE           0x0000  /* Invalid mode     */
#define X264_CSP_I400           0x0001  /* monochrome 4:0:0 */
#define X264_CSP_I420           0x0002  /* yuv 4:2:0 planar */
#define X264_CSP_YV12           0x0003  /* yvu 4:2:0 planar */
#define X264_CSP_NV12           0x0004  /* yuv 4:2:0, with one y plane and one packed u+v */
#define X264_CSP_NV21           0x0005  /* yuv 4:2:0, with one y plane and one packed v+u */
#define X264_CSP_I422           0x0006  /* yuv 4:2:2 planar */
#define X264_CSP_YV16           0x0007  /* yvu 4:2:2 planar */
#define X264_CSP_NV16           0x0008  /* yuv 4:2:2, with one y plane and one packed u+v */
#define X264_CSP_YUYV           0x0009  /* yuyv 4:2:2 packed */
#define X264_CSP_UYVY           0x000a  /* uyvy 4:2:2 packed */
#define X264_CSP_V210           0x000b  /* 10-bit yuv 4:2:2 packed in 32 */
#define X264_CSP_I444           0x000c  /* yuv 4:4:4 planar */
#define X264_CSP_YV24           0x000d  /* yvu 4:4:4 planar */
#define X264_CSP_BGR            0x000e  /* packed bgr 24bits */
#define X264_CSP_BGRA           0x000f  /* packed bgr 32bits */
#define X264_CSP_RGB            0x0010  /* packed rgb 24bits */
#define X264_CSP_MAX            0x0011  /* end of list */
#define X264_CSP_VFLIP          0x1000  /* the csp is vertically flipped */
#define X264_CSP_HIGH_DEPTH     0x2000  /* the csp has a depth of 16 bits per pixel component */

但是这个定义只是对于这个应用而言,对于其他的应用或者场景中,相同的数据格式却有着不同的名字,于是为了弄懂他们的差别关系,检索了一大堆信息,整理了一个图文出来如下。

- 阅读剩余部分 -