Samba协议实现视频上传、远程播放

一、效果演示

扫码打开上传页面,上传进度可以全局筛选订单查看,上传过程中查看视频是本地视频(速度快),上传完成后再次打开是smb服务器视频(打开慢)

本文涉及demo参考下载

二、集成smbj

1、集成smbj

java使用samba协议,主要用到了smbj库

gradle集成

implementation 'com.hierynomus:smbj:0.10.0'

maven集成

<dependency>
    <groupId>com.hierynomusgroupId>
    <artifactId>smbjartifactId>
    <version>0.10.0version>
dependency>

2、maven测试工程创建

直接在项目中测试比较麻烦,最好新建一个maven工程测试。如果初次新建maven项目,则需要配置仓库源为阿里镜像,并同步。

settings.xml


<settings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://maven.apache.org/SETTINGS/1.2.0"
    xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
    <mirrors>
        <mirror>
            <id>nexus-aliyunid>
            <mirrorOf>centralmirrorOf>
            <name>Nexus aliyunname>
            <url>http://maven.aliyun.com/nexus/content/groups/publicurl>
        mirror>
    mirrors>
settings>

三、smb操作

1、初始化连接配置

如果有上传流的操作,则需要开启共享读写,否则会造成文件一直被暂用情况(当然也可以让这个客户端断开连接)

public static void main(String[] args) throws Exception {
    String ip = "192.168.1.114";
    String userName = "";
    String password = "";
    String shareDir = "share";


    SMBClient client = new SMBClient();

    try (Connection connection = client.connect(ip)) {
        AuthenticationContext ac = new AuthenticationContext(userName, password.toCharArray(), "");
        Session session = connection.authenticate(ac);

        // Connect to Share
        try (DiskShare share = (DiskShare) session.connectShare(shareDir)) {
            Set<FileAttributes> fileAttributes = new HashSet<>();
            fileAttributes.add(FileAttributes.FILE_ATTRIBUTE_NORMAL);
            fileAttributes.add(FileAttributes.FILE_ATTRIBUTE_ARCHIVE);

            Set<SMB2CreateOptions> createOptions = new HashSet<>();
            createOptions.add(SMB2CreateOptions.FILE_NO_COMPRESSION);
            createOptions.add(SMB2CreateOptions.FILE_RANDOM_ACCESS);
            // 共享读、共享写
            Set<SMB2ShareAccess> smb2ShareAccesses = new HashSet<>();
            smb2ShareAccesses.add(SMB2ShareAccess.FILE_SHARE_WRITE);
            smb2ShareAccesses.add(SMB2ShareAccess.FILE_SHARE_READ);
            
            // 连接成功
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

2、文件上传

/**
 * 上传文件到远程
 *
 * @param host          IP地址
 * @param username      用户名
 * @param password      用户密码
 * @param path          共享目录
 * @param innerDir      远程内部文件夹
 * @param localFileName 本地文件
 */
public static void uploadFile(String host, String username, String password, String path, String innerDir, String localFileName) {
    DiskShare share = getDiskShare(host, username, password, path);
    try {
        // 如果目录不存在,逐层创建
        createRemoteDir(share, innerDir);

        Set<AccessMask> accessMasks = new HashSet<>();
        accessMasks.add(AccessMask.FILE_ADD_FILE);
        Set<FileAttributes> attributes = new HashSet<>();
        attributes.add(FileAttributes.FILE_ATTRIBUTE_NORMAL);
        Set<SMB2ShareAccess> smb2ShareAccesses = new HashSet<>();
        smb2ShareAccesses.add(SMB2ShareAccess.FILE_SHARE_WRITE);
        smb2ShareAccesses.add(SMB2ShareAccess.FILE_SHARE_READ);
        Set<SMB2CreateOptions> smb2CreateOptions = new HashSet<>();
        smb2CreateOptions.add(SMB2CreateOptions.FILE_RANDOM_ACCESS);

        // 文件名称: "tempDir/测试.mp4"
        String fileName = innerDir + "/" + localFileName.substring(localFileName.lastIndexOf("/") + 1);

        com.hierynomus.smbj.share.File openFile = share.openFile(fileName, accessMasks, attributes, smb2ShareAccesses, SMB2CreateDisposition.FILE_OVERWRITE_IF, smb2CreateOptions);
        OutputStream oStream = openFile.getOutputStream();
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(localFileName));
        byte[] buffer = new byte[1024*1024];
        int len = 0; //Read length
        while ((len = in.read(buffer, 0, buffer.length)) != -1) {
            oStream.write(buffer, 0, len);
        }
        oStream.flush();
        oStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

3、创建远程文件夹

/**
 * 创建远程目录
 *
 * @param share
 * @param dirName
 */
private static void createRemoteDir(DiskShare share, String dirName) {
    // 是否已存在
    if (share.folderExists(dirName)) {
        return;
    }

    // 目录不存在,逐层创建
    String[] fileNameArr = dirName.split("/");
    String tempDirName = ""; // 逐层目录

    for (String fileName : fileNameArr) {
        tempDirName += fileName + "/"; // 下一层目录

        if (share.folderExists(tempDirName)) {
            continue;
        }

        System.out.println("目录: " + tempDirName + " 不存在,即将创建");
        share.mkdir(tempDirName);
    }
}

4、下载远程文件

/**
 * 下载远程文件
 *
 * @param host       IP地址
 * @param username   用户名
 * @param password   用户密码
 * @param path       共享目录
 * @param remoteFile 远程文件, 可以是具体的文件,可以是匹配的文件
 * @param localDir   本地目标目录
 */
public static void downloadFile(String host, String username, String password, String path, String remoteFile, String localDir) {
    DiskShare share = getDiskShare(host, username, password, path);

    // 添加文件夹分隔符
    localDir = checkDirEnd(localDir);

    try {

        // 文件夹是否存在,创建本地目录
        createLocalDirIfNotExist(localDir);

        String remoteDir = "";
        for (FileIdBothDirectoryInformation f : share.list(remoteDir, remoteFile)) {
            String filePath = f.getFileName();

            String dstPath = localDir + f.getFileName();

            FileOutputStream fos = new FileOutputStream(dstPath);
            BufferedOutputStream bos = new BufferedOutputStream(fos);

            if (share.fileExists(filePath)) {
                System.out.println("正在下载文件: " + f.getFileName());

                com.hierynomus.smbj.share.File smbFileRead = share.openFile(filePath, EnumSet.of(AccessMask.GENERIC_READ), null, SMB2ShareAccess.ALL, SMB2CreateDisposition.FILE_OPEN, null);
                InputStream in = smbFileRead.getInputStream();
                byte[] buffer = new byte[4096];
                int len = 0;
                while ((len = in.read(buffer, 0, buffer.length)) != -1) {
                    bos.write(buffer, 0, len);
                }

                bos.flush();
                bos.close();

                System.out.println("文件下载成功, 保存在 " + dstPath);
            } else {
                System.out.println("文件 " + filePath + " 不存在");
            }
        }
    } catch (Exception e) {
        System.out.println("文件下载失败");
        e.printStackTrace();
    }
}

5、服务器拷贝

这个是通过磁盘IO,没有经过网络,速度可以达到几百MB每秒

String filePath1 = "wenjing/test/1.mp4";
File file1 = share.openFile(filePath1, EnumSet.of(AccessMask.GENERIC_READ), fileAttributes, SMB2ShareAccess.ALL, SMB2CreateDisposition.FILE_OPEN_IF, createOptions);

String filePath2 = "wenjing/test/1_jdk15.mp4";
File file2 = share.openFile(filePath2, EnumSet.of(AccessMask.GENERIC_WRITE), fileAttributes, SMB2ShareAccess.ALL, SMB2CreateDisposition.FILE_CREATE, createOptions);

file1.remoteCopyTo(file2);

6、更多功能与备注

更多功能:除了上述功能外,smb还支持list查看文件夹,删除文件夹、文件等

备注:在实际使用过程中,发现smbj库对于系统仍然有区别

1、macOS共享的smb:不支持服务器拷贝、不支持创建文件夹

2、linux共享的smb:一切正常

四、播放smb视频

播放smb链接视频需要用到vlc库,这个库相对较大(大概三十几MB),但是体验比自己写的流稳定。

implementation 'com.yyl.vlc:vlc-android-sdk:3.3.0'

跳转播放页面

Intent intent = new Intent(mContext, VlcPlayerActivity.class);
String path = "smb://dabaojiqi:[email protected]/mac/tempDir/测试.mp4";
intent.putExtra("videoPlayPath", path);
mContext.startActivity(intent);

VlcPlayerActivity相关android项目下载参考前面的"一、效果演示",内附demo下载链接

你可能感兴趣的:(音视频)