溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Android設(shè)備與外接U盤(pán)實(shí)現(xiàn)數(shù)據(jù)讀取操作的示例

發(fā)布時(shí)間:2020-10-20 00:24:59 來(lái)源:腳本之家 閱讀:436 作者:遲做總比不做強(qiáng) 欄目:移動(dòng)開(kāi)發(fā)

現(xiàn)在越來(lái)越多手機(jī)支持OTG功能,通過(guò)OTG可以實(shí)現(xiàn)與外接入的U盤(pán)等USB設(shè)備實(shí)現(xiàn)數(shù)據(jù)傳輸。

 USB OTG(On The Go)作為USB2.0的補(bǔ)充協(xié)議,于2001年由USB-IF提出。它提出的背景是移動(dòng)消費(fèi)類(lèi)電子產(chǎn)品的迅猛增加,而之前USB協(xié)議的主從協(xié)議標(biāo)準(zhǔn)讓這些電子產(chǎn)品在離開(kāi)PC電腦時(shí)的數(shù)據(jù)傳輸變得艱難,OTG技術(shù)正是為了解決這一問(wèn)題的標(biāo)準(zhǔn)。

Android設(shè)備與外接U盤(pán)實(shí)現(xiàn)數(shù)據(jù)讀取操作的示例

通過(guò)OTG技術(shù)實(shí)現(xiàn)設(shè)備間端到端互聯(lián)

OTG協(xié)議規(guī)定連接時(shí)默認(rèn)情況作為Host的設(shè)備為A設(shè)備,A設(shè)備負(fù)責(zé)為總線供電;默認(rèn)作為Device的設(shè)備為B設(shè)備(USB OTG標(biāo)準(zhǔn)在完全兼容USB2.0標(biāo)準(zhǔn)的基礎(chǔ)上,增加了一個(gè)ID pin;ID拉低為默認(rèn)A設(shè)備);而有些設(shè)備由于集成了Host控制器和Device控制器,既可以作A設(shè)備又可以做B設(shè)備,稱(chēng)為dura-role device。

最近項(xiàng)目上用到了該功能,項(xiàng)目上用的是安卓7.1的盒子,要實(shí)現(xiàn)與插入的U盤(pán)進(jìn)行數(shù)據(jù)操作。通過(guò)大量的找資料,終于實(shí)現(xiàn)了項(xiàng)目上需要的功能。找資料主要是解決兩個(gè)問(wèn)題:

  1. U盤(pán)權(quán)限問(wèn)題
  2. U盤(pán)文件路徑及文件操作

廢話不多說(shuō),感覺(jué)還是喜歡直接上代碼才爽快。項(xiàng)目中用到了一個(gè)開(kāi)源框架,開(kāi)源地址是:
https://github.com/magnusja/libaums。

代碼部分:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
  //輸入的內(nèi)容
  private EditText u_disk_edt;
  //寫(xiě)入到U盤(pán)
  private Button u_disk_write;
  //從U盤(pán)讀取
  private Button u_disk_read;
  //顯示讀取的內(nèi)容
  private TextView u_disk_show;
  //自定義U盤(pán)讀寫(xiě)權(quán)限
  private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
  //當(dāng)前處接U盤(pán)列表
  private UsbMassStorageDevice[] storageDevices;
  //當(dāng)前U盤(pán)所在文件目錄
  private UsbFile cFolder;
  private final static String U_DISK_FILE_NAME = "u_disk.txt";
  private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      switch (msg.what) {
        case 100:
          showToastMsg("保存成功");
          break;
        case 101:
          String txt = msg.obj.toString();
          if (!TextUtils.isEmpty(txt))
            u_disk_show.setText("讀取到的數(shù)據(jù)是:" + txt);
          break;
      }
    }
  };

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

  private void initViews() {
    u_disk_edt = (EditText) findViewById(R.id.u_disk_edt);
    u_disk_write = (Button) findViewById(R.id.u_disk_write);
    u_disk_read = (Button) findViewById(R.id.u_disk_read);
    u_disk_show = (TextView) findViewById(R.id.u_disk_show);
    u_disk_write.setOnClickListener(this);
    u_disk_read.setOnClickListener(this);
  }

  @Override
  public void onClick(View view) {
    switch (view.getId()) {
      case R.id.u_disk_write:
        final String content = u_disk_edt.getText().toString().trim();
        mHandler.post(new Runnable() {
          @Override
          public void run() {
            saveText2UDisk(content);
          }
        });

        break;
      case R.id.u_disk_read:
        mHandler.post(new Runnable() {
          @Override
          public void run() {
            readFromUDisk();
          }
        });

        break;
    }
  }

  private void readFromUDisk() {
    UsbFile[] usbFiles = new UsbFile[0];
    try {
      usbFiles = cFolder.listFiles();
    } catch (IOException e) {
      e.printStackTrace();
    }
    if (null != usbFiles && usbFiles.length > 0) {
      for (UsbFile usbFile : usbFiles) {
        if (usbFile.getName().equals(U_DISK_FILE_NAME)) {
          readTxtFromUDisk(usbFile);
        }
      }
    }
  }

  /**
   * @description 保存數(shù)據(jù)到U盤(pán),目前是保存到根目錄的
   * @author ldm
   * @time 2017/9/1 17:17
   */
  private void saveText2UDisk(String content) {
    //項(xiàng)目中也把文件保存在了SD卡,其實(shí)可以直接把文本讀取到U盤(pán)指定文件
    File file = FileUtil.getSaveFile(getPackageName()
            + File.separator + FileUtil.DEFAULT_BIN_DIR,
        U_DISK_FILE_NAME);
    try {
      FileWriter fw = new FileWriter(file);
      fw.write(content);
      fw.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
    if (null != cFolder) {
      FileUtil.saveSDFile2OTG(file, cFolder);
      mHandler.sendEmptyMessage(100);
    }
  }

  /**
   * @description OTG廣播注冊(cè)
   * @author ldm
   * @time 2017/9/1 17:19
   */
  private void registerUDiskReceiver() {
    //監(jiān)聽(tīng)otg插入 拔出
    IntentFilter usbDeviceStateFilter = new IntentFilter();
    usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
    usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
    registerReceiver(mOtgReceiver, usbDeviceStateFilter);
    //注冊(cè)監(jiān)聽(tīng)自定義廣播
    IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
    registerReceiver(mOtgReceiver, filter);
  }

  /**
   * @description OTG廣播,監(jiān)聽(tīng)U盤(pán)的插入及拔出
   * @author ldm
   * @time 2017/9/1 17:20
   * @param
   */
  private BroadcastReceiver mOtgReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
      String action = intent.getAction();
      switch (action) {
        case ACTION_USB_PERMISSION://接受到自定義廣播
          UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
          //允許權(quán)限申請(qǐng)
          if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
            if (usbDevice != null) {
              //用戶已授權(quán),可以進(jìn)行讀取操作
              readDevice(getUsbMass(usbDevice));
            } else {
              showToastMsg("沒(méi)有插入U(xiǎn)盤(pán)");
            }
          } else {
            showToastMsg("未獲取到U盤(pán)權(quán)限");
          }
          break;
        case UsbManager.ACTION_USB_DEVICE_ATTACHED://接收到U盤(pán)設(shè)備插入廣播
          UsbDevice device_add = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
          if (device_add != null) {
            //接收到U盤(pán)插入廣播,嘗試讀取U盤(pán)設(shè)備數(shù)據(jù)
            redUDiskDevsList();
          }
          break;
        case UsbManager.ACTION_USB_DEVICE_DETACHED://接收到U盤(pán)設(shè)設(shè)備拔出廣播
          showToastMsg("U盤(pán)已拔出");
          break;
      }
    }
  };

  /**
   * @description U盤(pán)設(shè)備讀取
   * @author ldm
   * @time 2017/9/1 17:20
   */
  private void redUDiskDevsList() {
    //設(shè)備管理器
    UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
    //獲取U盤(pán)存儲(chǔ)設(shè)備
    storageDevices = UsbMassStorageDevice.getMassStorageDevices(this);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
    //一般手機(jī)只有1個(gè)OTG插口
    for (UsbMassStorageDevice device : storageDevices) {
      //讀取設(shè)備是否有權(quán)限
      if (usbManager.hasPermission(device.getUsbDevice())) {
        readDevice(device);
      } else {
        //沒(méi)有權(quán)限,進(jìn)行申請(qǐng)
        usbManager.requestPermission(device.getUsbDevice(), pendingIntent);
      }
    }
    if (storageDevices.length == 0) {
      showToastMsg("請(qǐng)插入可用的U盤(pán)");
    }
  }

  private UsbMassStorageDevice getUsbMass(UsbDevice usbDevice) {
    for (UsbMassStorageDevice device : storageDevices) {
      if (usbDevice.equals(device.getUsbDevice())) {
        return device;
      }
    }
    return null;
  }

  private void readDevice(UsbMassStorageDevice device) {
    try {
      device.init();//初始化
      //設(shè)備分區(qū)
      Partition partition = device.getPartitions().get(0);
      //文件系統(tǒng)
      FileSystem currentFs = partition.getFileSystem();
      currentFs.getVolumeLabel();//可以獲取到設(shè)備的標(biāo)識(shí)
      //通過(guò)FileSystem可以獲取當(dāng)前U盤(pán)的一些存儲(chǔ)信息,包括剩余空間大小,容量等等
      Log.e("Capacity: ", currentFs.getCapacity() + "");
      Log.e("Occupied Space: ", currentFs.getOccupiedSpace() + "");
      Log.e("Free Space: ", currentFs.getFreeSpace() + "");
      Log.e("Chunk size: ", currentFs.getChunkSize() + "");
      cFolder = currentFs.getRootDirectory();//設(shè)置當(dāng)前文件對(duì)象為根目錄
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  private void showToastMsg(String msg) {
    Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
  }

  private void readTxtFromUDisk(UsbFile usbFile) {
    UsbFile descFile = usbFile;
    //讀取文件內(nèi)容
    InputStream is = new UsbFileInputStream(descFile);
    //讀取秘鑰中的數(shù)據(jù)進(jìn)行匹配
    StringBuilder sb = new StringBuilder();
    BufferedReader bufferedReader = null;
    try {
      bufferedReader = new BufferedReader(new InputStreamReader(is));
      String read;
      while ((read = bufferedReader.readLine()) != null) {
        sb.append(read);
      }
      Message msg = mHandler.obtainMessage();
      msg.what = 101;
      msg.obj = read;
      mHandler.sendMessage(msg);
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      try {
        if (bufferedReader != null) {
          bufferedReader.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
}

對(duì)應(yīng)布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.ldm.androidudisk.MainActivity"
    android:orientation="vertical">

  <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Android盒子外接U盤(pán)文件讀寫(xiě)測(cè)試DEMO"
      android:layout_gravity="center"
      android:layout_margin="10dp"
      />

  <EditText
      android:id="@+id/u_disk_edt"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_margin="10dp"
      android:hint="輸入要保存到U盤(pán)中的文字內(nèi)容"/>


  <Button
      android:id="@+id/u_disk_write"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_margin="10dp"
      android:gravity="center"
      android:text="往U盤(pán)中寫(xiě)入數(shù)據(jù)"/>

  <Button
      android:id="@+id/u_disk_read"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_margin="10dp"
      android:gravity="center"
      android:text="從U盤(pán)中讀取數(shù)據(jù)"/>

  <TextView
      android:id="@+id/u_disk_show"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="center"
      android:layout_marginLeft="10dp"
      />
</LinearLayout>

文件操作工具類(lèi):

package com.ldm.androidudisk.utils;

import android.os.Environment;

import com.github.mjdev.libaums.fs.UsbFile;
import com.github.mjdev.libaums.fs.UsbFileOutputStream;

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import static android.os.Environment.getExternalStorageDirectory;

/**
 * 文件操作工具類(lèi)
 *
 * @author ldm
 * @description:
 * @date 2016-4-28 下午3:17:10
 */
public final class FileUtil {
  public static final String DEFAULT_BIN_DIR = "usb";

  /**
   * 檢測(cè)SD卡是否存在
   */
  public static boolean checkSDcard() {
    return Environment.MEDIA_MOUNTED.equals(Environment
        .getExternalStorageState());
  }

  /**
   * 從指定文件夾獲取文件
   *
   * @return 如果文件不存在則創(chuàng)建, 如果如果無(wú)法創(chuàng)建文件或文件名為空則返回null
   */
  public static File getSaveFile(String folderPath, String fileNmae) {
    File file = new File(getSavePath(folderPath) + File.separator
        + fileNmae);
    try {
      file.createNewFile();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return file;
  }

  /**
   * 獲取SD卡下指定文件夾的絕對(duì)路徑
   *
   * @return 返回SD卡下的指定文件夾的絕對(duì)路徑
   */
  public static String getSavePath(String folderName) {
    return getSaveFolder(folderName).getAbsolutePath();
  }

  /**
   * 獲取文件夾對(duì)象
   *
   * @return 返回SD卡下的指定文件夾對(duì)象,若文件夾不存在則創(chuàng)建
   */
  public static File getSaveFolder(String folderName) {
    File file = new File(getExternalStorageDirectory()
        .getAbsoluteFile()
        + File.separator
        + folderName
        + File.separator);
    file.mkdirs();
    return file;
  }

  /**
   * 關(guān)閉流
   */
  public static void closeIO(Closeable... closeables) {
    if (null == closeables || closeables.length <= 0) {
      return;
    }
    for (Closeable cb : closeables) {
      try {
        if (null == cb) {
          continue;
        }
        cb.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  private static void redFileStream(OutputStream os, InputStream is) throws IOException {
    int bytesRead = 0;
    byte[] buffer = new byte[1024 * 8];
    while ((bytesRead = is.read(buffer)) != -1) {
      os.write(buffer, 0, bytesRead);
    }
    os.flush();
    os.close();
    is.close();
  }

  /**
   * @description 把本地文件寫(xiě)入到U盤(pán)中
   * @author ldm
   * @time 2017/8/22 10:22
   */
  public static void saveSDFile2OTG(final File f, final UsbFile usbFile) {
    UsbFile uFile = null;
    FileInputStream fis = null;
    try {//開(kāi)始寫(xiě)入
      fis = new FileInputStream(f);//讀取選擇的文件的
      if (usbFile.isDirectory()) {//如果選擇是個(gè)文件夾
        UsbFile[] usbFiles = usbFile.listFiles();
        if (usbFiles != null && usbFiles.length > 0) {
          for (UsbFile file : usbFiles) {
            if (file.getName().equals(f.getName())) {
              file.delete();
            }
          }
        }
        uFile = usbFile.createFile(f.getName());
        UsbFileOutputStream uos = new UsbFileOutputStream(uFile);
        try {
          redFileStream(uos, fis);
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    } catch (final Exception e) {
      e.printStackTrace();
    }
  }
}

不要忘記在app/build.grade下添加:

compile 'com.github.mjdev:libaums:0.5.5'

及AndroidManifest.xml中添加權(quán)限:

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

時(shí)間關(guān)系,就不貼圖了,歡迎指導(dǎo)交流。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI