在 Java 中使用 SMB 处理远程服务器中的共享文件

2021-08-25 11:13:28 浏览数 (7272)

介绍

我们习惯于使用共享文件,其中共享仅限于某些域中的用户或某些用户。远程应用程序需要访问共享资源并在共享位置执行添加、删除资源等操作。

服务器具有共享资源,这些资源通常在 Windows 机器中使用服务器消息块 (SMB) 协议 ( Server Message Block )。SMB 协议使应用程序能够访问远程服务器上的文件,以及允许客户端应用程序打开、读取、移动、更新远程服务器上的文件的其他资源。该资源仅限于某些用户。用户需要传递凭据才能访问共享资源。用户可以在共享资源上进行的活动在共享权限中定义。让我们假设用户具有读和写权限。

在本文中,我将为大家演示一个例子,其中应用程序需要使用一个简单的 Java 应用程序与 Windows 服务器计算机中的共享文件进行交互。用例做出以下假设:

  • 服务器是一台 Windows 机器。
  • 存在名为“ ​Test​”的本地用户,该用户的密码为“ ​Password​”。
  • 共享位置是“ 127.0.0.0.1\temp ”。
  • 用户“ ​Test​”有权访问共享位置“ temp ”,该位置可以位于 IP 为“ ​127.0.0.1​”的计算机中的任何位置。
  • 客户端应用程序可以访问网络。

代码库

我们正在设计的应用程序是在 Java 中使用 Maven 进行构建和依赖项管理。我正在使用 JCIFS,这是一个实现CIFS/SMB 网络协议的开源客户端库。该库可从 Maven Repository 获得

依赖关系显示在以下pom.xml文件中:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>fileShare</groupId>
    <artifactId>fileShare</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>7</source>
                    <target>7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>jcifs</groupId>
            <artifactId>jcifs</artifactId>
            <version>1.3.17</version>
        </dependency>
    </dependencies>
</project>

目前,该应用程序有一个文件Main.java,内容如下:

import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import java.net.MalformedURLException;

public class Main {
    public static void main(String[] args) {
        String url = "smb://127.0.0.1/test/";
        String userName = "test";
        String password = "password";
        String domain = null;
        NtlmPasswordAuthentication auth = 
              new NtlmPasswordAuthentication(null, userName, password);
        try {
            doRecursiveLookup(new SmbFile(url, auth));
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }
    /*
    * Recursively scans through the folder for files and prints the name of folder and file
    */
    public static void doRecursiveLookup(SmbFile smb) {
        try {
            if (smb.isDirectory()) {
                System.out.println(smb.getName());
                for (SmbFile f : smb.listFiles()) {
                    if (f.isDirectory()) {
                        doRecursiveLookup(f);
                    } else {
                        System.out.println("\t:" + f.getName());
                    }
                }
            } else {
                System.out.println("\t:" + smb.getName());
            }
        } catch (SmbException e) {
            e.printStackTrace();
        }
    }
}

这里,main方法使用for smb协议的url模式,并在第8行指向共享位置。局部变量for ​userName,password​和​domains​在第9到11行初始化,并在第13行验证用户,此时应用程序已成功连接到共享文件夹。

应用程序​SmbFile​在第 15 行创建一个对象并将该文件夹传递给​doRecursiveLookup(..)​第 24 行调用的方法。该方法简单地遍历共享位置中的所有文件和文件夹,并以递归方式在控制台中打印名称。请注意,​SmbFile​文件或文件夹的对象是相同的,并且​.isDirectory()​方法用于测试范围内的对象是文件还是文件夹。