最近需用使用java访问linux下的共享目录,实现文件下载和上传, 由于linux共享文件主要采用两种方式,samba和NFS,samba是基于Microsoft的smb/cifs协议, NFS网络文件系统(Network File System)则是另一种协议. 对这两种方式的配置和实现代码如下:(配置在Ubuntu下完成) 一,samba (1)配置: a ) 建立共享目录: mkdir /home/pirate/smbshare, chmod 777 smbshare b) 安装samba, sudo apt-get install samba, sudo apt-get install smbfs c) 修改samba配置文件, sudo gedit /etc/samba/smb.conf, 在文件最后添加如下行: [smbshare] #-----共享名字, 客户端访问时需使用这个名字 path = /home/pirate/smbshare available = yes browsealbe = yes public = yes writable = yes d) 创建共享用户: sudo useradd aaa f) 重启samba, sudo /etc/init.d/samba restart (2) java访问
访问Samba共享依赖于一个第三方包:jcifs-1.3.15.jar, 下载地址http://jcifs.samba.org/
Java代码
1. public void downloadViaShare(final String ip,final String user,final String password,final String <span style="color: #000000;">dir</span>)
2. {
3. "Share(SMB) download!");
4.
5. String newDir = dir;
6. "";
7. null;
8. null;
9. null;
10. byte [] buffer = new byte[8192];
11. int readBytes = 0;
12. int totalBytes = 0;
13.
14. if (!dir.endsWith("/")) //directory must end with "/"
15. "/";
16. "smb://"+user+":"+password+"@"+ip+"/"+newDir;
17.
18. long
19. try
20. new
21. if(shareDir.isDirectory())
22. {
23. fileList = shareDir.listFiles();
24. for(int i=0;i<fileList.length;i++)
25. {
26. if(fileList[i].isFile())
27. {
28. new
29. new FileOutputStream(new
30. while((readBytes = smbIs.read(buffer)) > 0
31. {
32. 0,readBytes);
33. totalBytes += readBytes;
34. }
35. smbIs.close();
36. fos.close();
37. " is downloaded!");
38. try
39. {
40. fileList[i].delete();
41. catch(SmbAuthException smbae )
42. {
43. " can not be deleted!");
44. }
45. }
46. }
47. long
48. long
49. "bytes downloaded in " + timeTaken/1000 + " seconds at "+ (( totalBytes / 1000 ) / Math.max( 1, ( timeTaken / 1000 ))) + "Kb/sec");
50. }
51. catch(MalformedURLException urle)
52. {
53. "Incorrect URL format!");
54. catch
55. smbe.printStackTrace();
56. this.getClass().getName()+"||"+smbe.getMessage());
57. catch(IOException ioe)
58. {
59. ioe.printStackTrace();
60. this.getClass().getName()+"||"+ioe.getMessage());
61. finally
62. {
63. try
64. {
65. smbIs.close();
66. fos.close();
67. catch(Exception smbe)
68. {
69. this.getClass().getName()+"||"+smbe.getMessage());
70. }
71. }
72.
73. }
二,NFS
(1) 配置
a) 安装NFS, sudo apt-get install nfs-kernel-server
b) 建立共享目录: mkdir /home/pirate/nfsshare
c) 编辑配置: sudo gedit /etc/exports ,在最后添加如下行:
/home/pirate/nfsshare *(rw,sync,no_all_squash),含义为:
共享目录 允许访问的网络段(读写权限,数据发送方式,客户端权限)
其它Ubuntu nfs常用的参数有: ro 只读访问 rw 读写访问sync 所有数据在请求时写入共享 async nfs在写入数据前可以响应请求 secure nfs通过1024以下的安全TCP/IP端口发送 insecure nfs通过1024以上的端口发送 wdelay 如果多个用户要写入nfs目录,则归组写入(默认) no_wdelay 如果多个用户要写入nfs目录,则立即写入,当使用async时,无需此设置。 hide 在nfs共享目录中不共享其子目录 no_hide 共享nfs目录的子目录 subtree_check 如果共享/usr/bin之类的子目录时,强制nfs检查父目录的权限(默认) no_subtree_check 和上面相对,不检查父目录权限 all_squash 共享文件的UID和GID映射匿名用户anonymous,适合公用目录。 no_all_squash 保留共享文件的UID和GID(默认) root_squash root用户的所有请求映射成如anonymous用户一样的权限(默认) no_root_squas root用户具有根目录的完全管理访问权限 anonuid=xxx 指定nfs服务器/etc/passwd文件中匿名用户的UID anongid=xxx 指定nfs服务器/etc/passwd文件中匿名用户的GID
d) 重启 NFS: sudo service portmap restart , sudo service nfs-kernel-server restart
e) 测试: showmount -e,查看是否有该目录的共享
(2) 代码
话说这段代码虽然很简单,却费了我不少力气。JDK本身是没有访问NFS的功能,只能用第三方包了,google后发觉用java访问NFS的应用很少,竟然没找到可用的示例,远不如samba那么多,而且只有sun的webnfs可用来访问NFS,在http://yanfs.dev.java.net 上只有一个一个的散装源码, 打包后的jar都没地方下,连API文档都没有. 愁煞我也. 找来找去,根据sun的在线文档摸索出了点头绪.
Java代码
1. public void downloadViaNFS(final String ip,final String user,final String password,final
2. {
3. "NFS download begin!");
4. try
5.
6. "nfs://"+ip+"/"+dir;
7. new
8. if
9. {
10. "URL is OK!");
11. else
12. {
13. "URL is bad!");
14. return;
15. }
16.
17. XFileExtensionAccessor nfsx = (XFileExtensionAccessor)xf.getExtensionAccessor();
18. if(!nfsx.loginPCNFSD(ip, user, password))
19. {
20. "login failed!");return;
21. }
22.
23. String [] fileList = xf.list();
24. null;
25. long
26. int filesz = 0;
27. for(String file:fileList)
28. {
29. new XFile(url+"/"+file);
30. new
31. new
32.
33. int
34. byte[] buf = new byte[8196];
35.
36.
37.
38. while ((c = in.read(buf)) > 0) {
39. filesz += c;
40. 0, c);
41. }
42.
43. " is downloaded!");
44. in.close();
45. out.close();
46. if
47. {
48. temp.delete();
49. " is deleted!");
50. else
51. {
52. " can not be delted!");
53. }
54. }
55. long
56. long
57. int rate = (int) ((filesz /1000) / (timeDiff / 1000.0));
58. " bytes copied @ " + rate + "Kb/sec");
59.
60. catch
61. logger.debug(e);
62. }
63.
64. }
• 首先在Linux上创建一个共享文件夹
mkdir /home/user/share
• 用root用户启动samba服务
service smb start
• 修改smb.conf文件
sudo gedit /etc/samba/smb.conf 或者 vi /etc/samba/smb.conf
[share]
path = /home/user/share
...
writable = yes
• 创建共享用户并设置密码
sudo useradd smbusr
sudo smbpasswd -a smbusr
使用命令 sudo smbpasswd -x 删除用户
• 重启samba服务
service smb restart
• 测试
在windows中输入//192.168.0.94,并输入用户名密码smbusr/***,看能不能访问到共享文件夹。如果可以的话拷贝一份本地txt文件到此目录,并在linux中查看此文件是否存在,如果用vi能够打开文件文件并正常查看其内容,congruatulations!
• 用jcifs测试文件操作
去下 载适当版本的jcifs,将jcifs-1.3.14.jar加入到项目工程中。写个测试类共享文件操作:
[java]
view plain
copy
1. public static void main(String[] args) {
2.
3. null;
4. null;
5. try {
6. new FileInputStream(new File("c:/source.txt"));
7. new SmbFileOutputStream(new SmbFile("smb://smbusr:smbusr@192.168.1.94/smbusr/dest.txt"));
8.
9. byte [] buffer = new byte[1024];
10. int c = 0;
11. while ((c = fis.read(buffer)) != -1) {
12. sfos.write(buffer);
13. }
14. catch (SmbException e) {
15. e.printStackTrace();
16. catch (MalformedURLException e) {
17. e.printStackTrace();
18. catch (UnknownHostException e) {
19. e.printStackTrace();
20. catch (IOException e) {
21. e.printStackTrace();
22. }
23.
24. finally {
25. try {
26. fis.close();
27. sfos.close();
28.
29. catch (IOException e) {
30. e.printStackTrace();
31. }
32. }
33. }
SAMBA的JAVA客户端JCIFS
首页
http://jcifs.samba.org/
下载文件
jcifs-1.2.25b.zip
下载的版本很新啊。能从MAVEN上搞到的版本如下pom.xml
<dependency>
<groupId>org.samba.jcifs</groupId>
<artifactId>jcifs</artifactId>
<version>1.2.15</version>
</dependency>
提供调用的static 工具类SambaUtil.java:
package com.sillycat.api.commons.utils;
import java.net.MalformedURLException;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import jcifs.smb.SmbFileInputStream;
import jcifs.smb.SmbFileOutputStream;
public class SambaUtil {
public static void delete(String filepath, String username, String pwd)
{
SmbFile f = null;
try {
f = new SmbFile("smb://" + username + ":" + pwd + "@"
+ filepath);
try {
if (f.exists()) {
f.delete();
}
} catch (SmbException e) {
e.printStackTrace();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
public static boolean exists(String filepath, String username, String pwd)
throws Exception {
SmbFile file = new SmbFile("smb://" + username + ":" + pwd + "@"
+ filepath);
try {
return file.exists();
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public static boolean filerename(String filepath, String newFilename,
String username, String pwd) {
try {
SmbFile f = new SmbFile("smb://" + username + ":" + pwd + "@"
+ filepath);
if (f.isFile()) {
String str = filepath.substring(0, filepath.lastIndexOf("/"));
str = "smb://" + username + ":" + pwd + "@" + str + "/"
+ newFilename;
f.renameTo(new SmbFile(str));
} else if (f.isDirectory()) {
String str = filepath.substring(0, filepath.length() - 1);
str = filepath.substring(0, str.lastIndexOf("/"));
str = "smb://" + username + ":" + pwd + "@" + str + "/"
+ newFilename;
f.renameTo(new SmbFile(str));
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public static void mkdir(String dir, String username, String pwd) {
try {
SmbFile f = new SmbFile("smb://" + username + ":" + pwd + "@" + dir);
if (!f.exists()) {
f.mkdir();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void mkfile(String filepath, String username, String pwd) {
try {
SmbFile f = new SmbFile("smb://" + username + ":" + pwd + "@"
+ filepath);
if (!f.exists()) {
f.createNewFile();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void mkfile(String filepath, String username, String pwd,
String content) {
try {
SmbFile f = new SmbFile("smb://" + username + ":" + pwd + "@"
+ filepath);
if (!f.exists())
f.createNewFile();
writefile(filepath, content, username, pwd);
} catch (Exception e) {
e.printStackTrace();
}
}
public static String readfile(String filepath, String username, String pwd) {
StringBuffer sb = new StringBuffer("");
try {
SmbFile f = new SmbFile("smb://" + username + ":" + pwd + "@"
+ filepath);
if (f.exists() && f.isFile()) {
int length = f.getContentLength();// 得到文件的大小
byte buffer[] = new byte[length];
SmbFileInputStream in = new SmbFileInputStream(f);
while ((in.read(buffer)) != -1) {
sb.append(new String(buffer));
}
in.close();
}
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
public static boolean isdir(String filepath, String username, String pwd)
throws Exception {
String dir = "smb://" + username + ":" + pwd + "@" + filepath;
SmbFile f = new SmbFile(dir);
return f.isDirectory();
}
public static void writefile(String filepath, String content,
String username, String pwd) {
try {
SmbFile to = new SmbFile("smb://" + username + ":" + pwd + "@"
+ filepath);
SmbFileOutputStream out = new SmbFileOutputStream(to);
out.write(content.getBytes());
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试类SambaUtilTest.java:
package com.sillycat.api.commons.utils;
import junit.framework.TestCase;
public class SambaUtilTest extends TestCase {
protected void setUp() throws Exception {
super.setUp();
}
protected void tearDown() throws Exception {
super.tearDown();
}
public void testDummy() {
assertTrue(true);
}
public void testCreateDir() {
String dir = "www.sillycat.com/share/test1";
SambaUtil.mkdir(dir, "guest", "guest");
SambaUtil.mkfile(dir + "/test2.txt", "guest", "guest", "<html></html>中文hello world!");
String tmp = SambaUtil.readfile(dir + "/test2.txt", "guest", "guest");
System.out.println(tmp);
SambaUtil.delete(dir + "/test2.txt", "guest", "guest");
}
}
报错:
jcifs.smb.SmbException: The network name cannot be found.
原来是我的filepath写错了,写成www.sillycat.com/test1
改成www.sillycat.com/share/test1就OK了
报错:
jcifs.smb.SmbException: The process cannot access the file because it is being used by another process.
原来是方法里面的
SmbFileInputStream in = new SmbFileInputStream(f);
SmbFileOutputStream out = new SmbFileOutputStream(to);
这个in 和 out 都要注意 close,我有一个忘记close了。。。汗