Organizationally unique identifier (OUI) “组织唯一标识符”,是IEEE分发给各个厂家的唯一MAC标识符。
官方地址为:http://standards-oui.ieee.org/oui.txt
我们知道,设备的MAC地址由12位数字和字母混合组成,这里需要注意的是:MAC地址的前六位代表唯一的厂商,且MAC地址中的英文字符取值范围为A~F。
考虑这样一个需求,我们需要在自己的应用中查找某一个MAC对应的厂商,有两个方法可以实现:
直接把oui.txt下载到本地,然后将txt文件放到res文件夹下的raw文件夹下,然后在代码中直接查询,如下所示:
InputStream inputStream = context.getResources().openRawResource(R.raw.oui);
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(inputStreamReader);
String line;
try {
while ((line = reader.readLine()) != null) {
if (line.contains(mac)) {
return line; //获取到型号行
}
}
} catch (IOException e) {
e.printStackTrace();
}
这样做的好处在于方便,坏处也显而易见:性能太低。
第二种方法是将oui.txt先格式化,然后将格式化的新的txt文件读取到数据库中,这样在应用中查询时将直接查询sqlite数据库,查询时间将大大缩短。
那么首先我们把oui.txt文件格式化,新的文件我们命名为new_oui.txt(需要注意的点已经写在代码注释中):
public class FileConvert {
public static void main(String[] args){
try{
FileReader fr = new FileReader(new File("/Users/admin/Downloads/oui.txt"));
BufferedReader br = new BufferedReader(fr);
FileWriter fw = new FileWriter(new File("/Users/admin/Downloads/new_oui.txt"));
String str;
String tempStr;
while ((str = br.readLine()) != null) {
if(str.equals("") || str.length() < 7){
continue;
}
tempStr = str.substring(0,6);
if(regexTest(tempStr)){//检查某一行的前六位是否是mac,如果是则进行抽取
str = tempStr + " " + str.substring(22);//从第22位字符开始的是厂商名字,将6位的mac和厂商名字拼接起来
fw.write(str + "\n");
}
}
br.close();
fr.close();
fw.flush();
fw.close();
}catch (FileNotFoundException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
}
public static boolean regexTest(String str){
Pattern r = Pattern.compile("^[A-F0-9]{6}$");//mac的前六位由英文A~F及数字0-9构成
Matcher m = r.matcher(str);
return m.matches();
}
}
经过这样一步操作后,我们得到了新的txt文件:
接下来要做的是从新的txt文件中读取数据到sqlite的db文件中:
首先把new_oui.txt放到raw文件夹下,然后把它读取到应用在本机中的本地文件夹下:
public static void writeFile(){
try {
if(!(new File("/data/data/xxx.xxx.xx/new_oui.txt").exists())){
InputStream is = MyApplication.getContext().getResources().openRawResource(
R.raw.new_oui);
FileOutputStream fos = new FileOutputStream("/data/data/xxx.xxx.xx/new_oui.txt");
byte[] buffer = new byte[400000];
int count;
while ((count = is.read(buffer)) > 0) {
fos.write(buffer, 0, count);
}
fos.close();
is.close();
}
}catch (FileNotFoundException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
}
然后,我们开始把new_oui.txt中的数据导入到db文件中,这里为了方便,我并没有构造一个新的db文件,而是从网上下载了一个db文件,然后将其进行重写:
public static void rewriteDb(){
deleteAll();
try{
FileReader fr = new FileReader(new File("/data/data/xxx.xx.xxx/new_oui.txt"));
BufferedReader br = new BufferedReader(fr);
String str;
String mac;
String factory;
while ((str = br.readLine()) != null) {
if(str.equals("") || str.length() < 7){
continue;
}
mac = str.substring(0,6);
factory = str.substring(7,str.length());
DeviceFactoryEntity entity = new DeviceFactoryEntity();
entity.threeByteMac = mac;
entity.factory = factory;
insert(entity);
}
br.close();
fr.close();
}catch (FileNotFoundException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
}
public static void deleteAll(){
try {
String sqlDeleteData = "DELETE FROM device_factory_entity";
getInstance().db.execSQL(sqlDeleteData);
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void insert(DeviceFactoryEntity entity){
if(entity != null){
ContentValues values = new ContentValues();
values.put("three_byte_mac",entity.threeByteMac);
values.put("factory",entity.factory);
getInstance().db.insert("device_factory_entity",null,values);
}
}
完成以后,就可以愉快的用sqlite去查询MAC对应的厂商名啦。
这里给出一个db文件的下载,db文件中的数据对应2018年9月底的oui.txt: