USBCopyer 回调功能详细说明

“回调” 是 USBCopyer V5.0 新引入的一个概念,它用于在 USBCopyer 执行特定操作时触发用户指定的代码或程序,以便实现某种高级的、程序没有提供的功能。

基本使用方法:

  1. 在USBCopyer设置打开回调的开关
  2. 打开USBCopyer所在目录下的 USBCopyer\USBCopyerSystem 文件夹
  3. 建立 回调名字.bat ,例如 AllCompletedCallback.bat
  4. 在里面写代码。可用的变量如下:

可用变量

书写以下内容就会被USBCopyer自动转换成相应的值。

变量名 说明
{$SystemDir} USBCopyer 所在目录
{$SystemVer} USBCopyer 版本号 例如 5.0.0.0
{$DataDir} USBCopyerData 所在目录(设置的数据目录)
{$USBDir} 本次复制所得的文件所在目录,不含{$DataDir}
{$VolumeSerialNumber} 磁盘序列号
{$VolumeName} 磁盘卷标(名字)
{$Volume} 磁盘盘符,例如G:
{$DriveType} 磁盘种类(返回数字)

磁盘种类:

1
2
3
4
5
6
7
Unknown (0)   
No Root Directory (1)
Removable Disk (2)
Local Disk (3)
Network Drive (4)
Compact Disc (5)
RAM Disk (6)

具体回调说明

当回调运行时,基准目录是 USBCopyer 所在目录下的 USBCopyerData\USBCopyerSystem 文件夹(无视数据目录设置)
回调的所有输出都会被捕获,并记入日志。

回调:AllCompletedCallback

在磁盘文件全部复制后触发,可以用于调用Git实现版本控制、调用云盘客户端实现上传等
当 USBCopyer 变成空闲状态时,便会创建一个新线程运行此回调

回调:DiskDetectedCallback

当磁盘插入时触发。可用于做复制判断
若 “(回调2)等待完成,并只允许返回0时复制” 启用,则该回调将阻塞复制线程,并在回调完成后且退出码为0时继续复制。
若上述设置未启用,则该回调对复制线程没有影响。
变量{$USBDir}不可用。强行获取将得到NONE

玩法实例:使用GIT进行版本控制

首先安装最新版本的 Git,安装过程一路 Next 即可
然后在 USBCopyerData 打开命令行或Powershell(win10为资源管理器点击左上角文件),输入:git init
然后保存以下代码到:USBCopyerData\USBCopyerSystem 文件夹,命名为 AllCompletedCallback.bat

1
2
3
4
5
6
7
@echo off
echo USBCopyer Git Tool // Written by Kenvix
echo USBCopyer Version: {$SystemVer}
cd ..
git add .
git commit --author "USBCopyer <[email protected]>" -m "AutoCommit: {$USBDir}" .
exit %ERRORLEVEL%

C# 实现自定义"应用程序设置"的配置文件(user.config)存储路径

关于“应用程序设置”: 前往MSDN查看

默认提供的 SettingsProvider 不允许我们修改应用程序设置的配置文件的路径,这就导致了以下问题:

  1. 设置保存在了 %appdata% 目录下,使应用程序不够绿色化
  2. 当用户把程序拷贝到其他电脑上时,设置将丢失
  3. 当用户升级程序时,设置将丢失(自带的 Upgrade() 过于复杂)

要解决上述问题,就需要由我们自己来定义在哪里存储应用程序设置
MSDN给出的方法是:自己实现一个 SettingsProvider

Java 学习笔记 (仍在更新)

Java 学习笔记 #3

by kenvix @ 2018-11-10 pm

概念这种东西就是应付考试,实际生产中懂概念的不如有经验的。

多态

概念: 相同类型的变量、调用同一个方法时呈现出多种不同的行为特征,称为多态。

Java 中的多态与 TypeScript, C# 中的多态

这三种语言的处理策略不同,涉猎语言较多的用户可能会因此写出 Bug。

Upcasting in C

考虑代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Father
{
public void Test()
{
Console.WriteLine("father");
}
}
class Child : Father
{
public void Test() //equals: public new void Test()
{
Console.WriteLine("child");
}
}

class Program
{
static void Main(string[] args)
{
Father father = new Child();
father.Test();
}
}

输出:father

Upcasting in java

考虑代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

class Sunzi extends Test {
public void child() {
System.out.println("child!");
}

@Override
public void nmbd() {
System.out.println("extend!sunzi");
}
}

public class Test {
public void nmbd() {
System.out.println("super!");
}

public void father() {
System.out.println("father!");
}
}

Test test = (Test)new Sunzi();
test.nmbd();

输出:extend!sunzi

Java 中,test 的 运行时类型是 Sunzi 而不是 Test,这就导致其方法特征始终呈现为子类的特征,即实际调用了子类的方法
而在编译其则呈现父类特征,即你不能调用 test.child();

Note: 实例变量与 C# 相同,均为父类的实例变量。

Upcasting in TypeScript

考虑以下 TypeScript 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class father {
public test() {
console.log("father");
}
}

class child extends father{
public test() {
console.log("child");
}
}

const f: father = new child();
f.test();

输出:child
TypeScript 最终是要类型擦除输出JavaScript的,这种类型注解没有任何意义。

拆装箱

即对 基本数据类型 和 包装类型 的直接赋值操作,等效过时的new, getValue。

++ Object 是它们的子类,因此有这种智障操作:

1
2
Object obj = 666; //自动 upcasting
int i = (Integer)obj; //用作编译期

许多智障面试官也许会出这种问题

1
2
3
4
5
6
7
8
Integer a = 1;
Integer b = 1;
a == b // true
b = 199;
a == b //false (unlinked)
Integer c = 666;
Integer d = 666;
c == d //false

Java 对 -128~127 的 Integer 进行了缓存,故 a b 指向同一个数据。

立刻转 C# 保平安。

字符串常量池

1
2
3
4
5
6
7
String str1 = new String("fuck");
String str2 = new String("fuck");
String str3 = "fuck";
String str4 = "fuck";
System.out.println(str1==str2); //false
System.out.println(str1==str3); //false
System.out.println(str4==str3); //true

直接使用 String x = “” 表达式赋值的字符串由 JVM 常量池直接接管,相同的字符串引用将指向池中相同的值。
而 String str1 = new String(“fuck”); 则创建了字符串对象到 heap。

IDEA 明确告诉你这种方法很垃圾,但是sb面试官还是要问。

Java 学习笔记 #2

by kenvix @ 2018-11-07 am

java学得越深,越发觉得kotlin香

数据类型

参数传递

java 仅有值传递。传递一个对象时,传递该引用该对象的变量的拷贝(stack中产生引用变量的副本),但引用相同的对象,heap没有改变。
Python和java相反,只有引用传递。不过,Python的引用传递很有意思,改变实参基本类型的值不会影响形参,这是因为指了个新的。

数据类型和内存分配

基础数据类型(Value type)直接在栈(stack)空间分配,方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收。

引用数据类型,需要用new来创建,既在栈空间分配一个地址空间(reference),又在堆空间分配对象的类变量(object)。方法的引用参数,在栈空间分配一个地址空间,并指向堆空间的对象区,当方法调用完成后从栈空间回收。

静态变量在heap的方法区储存。

类成员实例变量储存在heap,证明了之前成员变量性能低的猜想。

JVM细节

每一个Java应用都唯一对应一个JVM实例,每一个实例唯一对应一个堆,而每个线程包含一个栈区

类 包 对象

java的getter setter就是狗屎

import

实现import as的技巧 实现导入同名类
import com.text.Formatter;
private Formatter textFormatter;
private com.json.Formatter jsonFormatter;

import static导入可以导入类的静态成员,但垃圾java缺少as的支持使得污染问题十分严重

构造方法

如果签名一致,若子类构造器没有显式调用父类构造器,将隐式调用。

初始化顺序: 静态初始化块-普通初始化块-构造器

Java 学习笔记 #1

by kenvix @ 2018/11/06

Lambda (#1) ->

变量作用域: lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。

声明和使用

1
2
3
4
5
6
7
8
9
10
@FunctionalInterface
interface excited {
void gg(String message);
}

public static void main(String[] args) {
excited fff = message -> System.out.println("lambda block called");

fff.gg("fuck!!!");
}

此接口要求必须是函数式接口,如果其中有两个方法则lambda表达式会编译错误。但java8的新特性如许实现如下写法:

1
2
3
4
5
6
interface MathOperation {
int operation(int a, int b);
default int addition(int a, int b){
return a+b;
}
}

泛型

基本类型不能作为类型参数

泛形要求能包容的是对象类型,而基本类型在java里不属于对象
但是基本类型都有其包装类型,也就是对象类型

大括号

1. 作用域

创建一个新的作用于防止变量污染

2. 声明匿名类

1
2
3
new Object() {
//content of anymous class
};

3. 类的初始化块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.util.HashMap;

public class Test {
private static HashMap<String, String> map = new HashMap<String, String>() {
{
put("Name", "June");
put("QQ", "2572073701");
}
}; //可以在初始化时为HASHMAP赋值

public int nonStatic;

static { //静态块
System.out.println("Static block called");
}

{ //类的初始化块1
System.out.println("Init block called");
}

Test() {
System.out.println("Constrator block called");
}

{ //类的初始化块2
nonStatic = 555;
System.out.println("Init2 block called");
}

public void nmbd() {}

static {
System.out.println("Static2 block called");
}
}

OUTPUT:

1
2
3
4
5
Static block called
Static2 block called
Init block called
Init2 block called
Constrator block called

结合匿名类使用:

1
2
3
4
5
new Object() {
{
System.out.println("called!");
}
};