socket編程機制:客戶端與服務端通過socket套接字連接後都會返回一個實例對象,分別保存這個對象,就相當於保存的對方的地址。Socket理解爲一個可以連通網絡上不同計算機程序之間的管道,把一堆數據從管道的A端扔進去,則會從管道的B端出來。管道的端口由兩個因素來唯一確認,即機器的IP地址和程序所使用的端口號。端口號就是程序員指定的一個數字,許多著名的木馬程序在網絡上掃描不同的端口號就是爲了獲取一個可以連通的端口從而進行破壞。程序不要使用太小的端口號,它們一般被系統佔用了,也不要使用一些常用的端口,一般來說使用1000~5000之內的端口比較好。
實現功能:
1.實現手機相冊中的單個圖片上傳到電腦指定路徑。(手機相冊存在固定位置/sdcard/DCIM/Camera/...)
輸入*.jpg,*.jpeg等
2.修改之前上傳固定位置的單個圖片爲輸入相冊中的多個圖片名稱,用逗號“,”分隔開,然後上傳到電腦,提示用戶是否上傳成功。
3.因爲上傳照片很難分清哪個照片需要添加照片描述,後來想使用ExpandableListView下拉列表讓用戶選擇圖片內容類型,選擇後自動添加到輸入框和圖片名稱以“:”分開,上傳電腦以此描述類型命名爲圖片名稱,爲防止圖片重名,前面加上上傳時原圖片名稱,上傳同一張圖片時纔會發生覆蓋,不會引起圖片丟失,還能直觀查看圖片內容描述。
4.改善項目功能範圍太小的缺陷,添加輸入手機內某個文件所在路徑,就可獲取路徑下的所有圖片全部上傳到電腦。
注意:測試時最好用真機,否則虛擬機虛擬內存沒有圖片無法測試功能是否成功。
1.首先搭建好客戶端環境,新建android-project ,新建activity
將手機中的圖片發送字節給服務端
2.創建手機界面佈局mainactivity.xml
界面中有textview、EditText、Button、ExpandableListView控件
這裏的界面效果:
3.MainActivity----socket客戶端:接收手機圖片信息並處理
完成任務1.在固定路徑下(sdcard/./.)查找圖片文件,輸入圖片名稱實現上傳,
2.實現輸入手機內圖片文件的絕對路徑,然後點擊上傳按鈕,可將圖片上傳到電腦指定位置。服務器來接收圖片並指定存放位置。
3.實現選擇圖片的類型並將其圖片複製後重命名,以便用戶在電腦分辨圖片內容並使用。
4.ExpandableListView下拉列表的的學習和使用,重寫下拉列表適配器,顯示自定義樣式
5.截取原圖片的名稱使其與圖片內容類型共同組成上傳後的圖片名稱。例如:a.jpg 圖片內容類型爲旅遊,則重命名的名稱爲旅遊a.jpg
public class UploadPhotoActivity extends Activity {
private Socket socket;
private String ip = "10.11.204.34";//電腦ip地址,在本地連接的屬性下查找本機地址
private int port = 4652;//端口號
String[] imgStrings;
BufferedReader reader;
ExpandableListView exp;
File file;
boolean result = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_upload_photo);
查找組件img 、seriesUpload、filePath、exp。。。。
exp.setAdapter(getAdapter());
//點擊子視圖文本觸發事件
exp.setOnChildClickListener(new OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
String nowString=img.getText().toString().concat(":"+getAdapter().getChild(groupPosition, childPosition).toString());
img.setText(nowString);
exp.collapseGroup(0);//選擇子文本後收縮下拉列表
return false;
}
});
//根據圖片名稱實現上傳
mButton.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
String strString = img.getText().toString();
imgStrings = new String[] {};
if (strString.trim().length() == 0)
return;
if (strString.contains(",")) {// 多張圖片上傳
imgStrings = strString.split(",");
for (int i = 0; i < imgStrings.length; i++) {
if(imgStrings[i].contains(":"))
upload(imgStrings[i].split(":")[0],imgStrings[i].split(":")[1]);
else
upload(imgStrings[i], "");
getResult(i+1);
}
} else {//只傳一張圖片
if(strString.contains(":")){//選擇圖片描述
upload(strString.split(":")[0],strString.split(":")[1]);
}
else//沒有選擇圖片描述
upload(strString, "");
getResult(1);
}
}
});
//根據文件夾路徑上傳文件內一系列圖片
seriesUpload.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
String pathString = filePath.getText().toString();
imgStrings = new String[] {};
if (pathString.trim().length() == 0)
return;
String[] paths=listFile(filePath.getText().toString());
if (paths.length==0) {// 文件夾沒有圖片
Toast.makeText(UploadPhotoActivity.this, "文件夾內沒有可傳圖片文件!",
Toast.LENGTH_SHORT).show();
return;
} else {
for (int j = 0; j < paths.length; j++) {
seriesUpload(paths[j]);
getResult(j);//提示是否已上傳成功
}
}
}
});
}
//i代表上傳的圖片索引,返回上傳結果
private void getResult(int i) {
if (file.length() != 0)
Toast.makeText(UploadPhotoActivity.this, "上傳成功!",
Toast.LENGTH_SHORT).show();
else
Toast.makeText(UploadPhotoActivity.this, "第"+i+"張上傳失敗,不存在此文件",
Toast.LENGTH_SHORT).show();
}
//得到文件夾下的所有圖片絕對路徑
public String[] listFile(String derect) {
File file = new File(derect);
File[] f = file.listFiles();
String Path[] = new String[f.length];
for (int i = 0; i < f.length; i++)
{
Path[i] = f[i].getPath();
System.out.println(Path[i]);
}
return Path;
}
// 根據圖片名稱上傳照相機中單個照片
private void upload(String path,String scrip) {
DataOutputStream dos;
FileInputStream fis;
try {
///sdcard/DCIM/Camera/照相機拍攝後圖片所存路徑
file = new File("/sdcard/DCIM/Camera/" + path.trim());
if (file.length() == 0) {
return;
} else {
socket = new Socket(ip, port);
dos = new DataOutputStream(socket.getOutputStream());
fis = new FileInputStream(file);
dos.writeUTF(path.substring(0,path.indexOf("."))+scrip+path.substring(path.indexOf(".")));
dos.flush();
byte[] sendBytes = new byte[1024 * 8];
int length;
while ((length = fis.read(sendBytes, 0, sendBytes.length)) > 0) {
dos.write(sendBytes, 0, length);
dos.flush();// 發送給服務器
}
dos.close();//在發送消息完之後一定關閉,否則服務端無法繼續接收信息後處理,手機卡機
/*reader = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
result = Boolean.parseBoolean(reader.readLine().toString());
System.out.println("上傳結果" + result);//運行時總是提示socket關閉,不能接收服務端返回的消息
reader.close();*/
fis.close();
socket.close();
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (SocketTimeoutException e) {
e.printStackTrace();
Toast.makeText(UploadPhotoActivity.this, "超時,上傳失敗",
Toast.LENGTH_LONG).show();
}catch (IOException e) {
e.printStackTrace();
}
}
//根據文件夾路徑上傳所有的圖片到服務器
//此dirpath是圖片絕對路徑
private void seriesUpload(String dirpath) {
DataOutputStream dos;
FileInputStream fis;
try {
file = new File(dirpath);
if (file.length() == 0) {
return;
} else {
socket = new Socket(ip, port);
dos = new DataOutputStream(socket.getOutputStream());
fis = new FileInputStream(file);
dos.writeUTF(dirpath.substring(dirpath.lastIndexOf("/")+1));//截取圖片名稱
dos.flush();
byte[] sendBytes = new byte[1024 * 8];
int length;
while ((length = fis.read(sendBytes, 0, sendBytes.length)) > 0) {
dos.write(sendBytes, 0, length);
dos.flush();// 發送給服務器
}
dos.close();//在發送消息完之後一定關閉,否則服務端無法繼續接收信息後處理,手機卡機
fis.close();
socket.close();
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (SocketTimeoutException e) {
e.printStackTrace();
Toast.makeText(UploadPhotoActivity.this, "超時,上傳失敗",
Toast.LENGTH_LONG).show();
}catch (IOException e) {
e.printStackTrace();
}
}
//下拉列表適配器設置成自己需要的樣式
private ExpandableListAdapter getAdapter(){
final String[] generalsTypes = new String[] { "圖片分類"};
//子視圖顯示文字
final String[] generals = new String[] { "地方特色風景", "個人生活寫照、旅遊懷念","地圖拍攝","美食", "工作需求圖片", "辦公環境寫實","天氣圖片","幸福一家人", "好友、同事照片", "汽車","明星寫真"};
//重寫adapter類,創建新適配置
ExpandableListAdapter adapter=new ExpandableListAdapter(){
@Override
public boolean areAllItemsEnabled() {return false;}
@Override
public Object getChild(int groupPosition, int childPosition) {
return generals[childPosition];
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
LinearLayout ll = new LinearLayout(
UploadPhotoActivity.this);
ll.setOrientation(0);
TextView textView = new TextView(UploadPhotoActivity.this);
AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT, 64);
textView.setLayoutParams(lp);
textView.setGravity(Gravity.CENTER_VERTICAL);
textView.setPadding(36, 0, 0, 0);
textView.setTextSize(18);
textView.setText(getChild(groupPosition, childPosition)
.toString());
ll.addView(textView);
return ll;
}
@Override
public int getChildrenCount(int groupPosition) {return generals.length;}
@Override
public Object getGroup(int groupPosition) {return generalsTypes[groupPosition];}
@Override
public int getGroupCount() {return generalsTypes.length;}
@Override
public long getGroupId(int groupPosition) {return groupPosition;}
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
LinearLayout ll = new LinearLayout( UploadPhotoActivity.this);
ll.setOrientation(0);
TextView textView = new TextView(UploadPhotoActivity.this);
AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT, 50);
textView.setLayoutParams(lp);
textView.setGravity(Gravity.CENTER_VERTICAL);
textView.setPadding(80, 5, 0, 0);
textView.setTextSize(20);
textView.setTextColor(Color.BLACK);
textView.setText(getGroup(groupPosition).toString());
ll.addView(textView);
return ll;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public boolean isChildSelectable(int groupPosition,
int childPosition) {
return true;
}
@Override。。。。。。一系列要實現的父類的方法
};
return adapter;
}
}
4.創建服務器端,新建java-project,在main方法中寫入服務器接收信息代碼
服務端接收字節寫入本地電腦文件內
//服務器
public class TransFileServer {
public static void main(String[] args) {
uploadThread t = new uploadThread();
t.start();
}
}
class uploadThread extends Thread {
private static final int HOST_PORT = 4652;
DataInputStream inputStream;
FileOutputStream fos;
boolean flag = false;
@Override
public void run() {
Socket skt = null;
try {
ServerSocket server = new ServerSocket(HOST_PORT);
while (true) {
skt = server.accept();
System.out.println("接收到Socket請求");
//接收客戶端文件
inputStream = new DataInputStream(skt.getInputStream());
PrintWriter writer = new PrintWriter(skt.getOutputStream());
String trueName = inputStream.readUTF();
fos = new FileOutputStream("D://" + trueName);
byte[] inputByte = new byte[1024 * 8];
int length;
while ((length = inputStream.read(inputByte,0,inputByte.length)) > 0) {
System.out.println("正在接收數據..." + length);
flag = true;
fos.write(inputByte, 0, length);
fos.flush();
}
System.out.println("圖片接收完成");
fos.close();
inputStream.close();
// 服務器發送消息
writer.println(flag);// 返回是否接收到圖片
writer.flush();
writer.close();
skt.close();
}
}catch (IOException e) {
e.printStackTrace();
}
}
}
5.可選擇使用較完善的獲取圖片列表方法代碼段:
public List<STRING> getPictures(final String strPath) {
List<STRING> list = new ArrayList<STRING>();
File file = new File(strPath);
File[] files = file.listFiles();
if (files == null) {
return null;
}
for(int i = 0; i < files.length; i++) {
final File f = files[i];
if(f.isFile()) {
try{
int idx = f.getPath().lastIndexOf(".");
if (idx <= 0) {
continue;
}
String suffix = f.getPath().substring(idx);
if (suffix.toLowerCase().equals(".jpg") ||
suffix.toLowerCase().equals(".jpeg") ||
suffix.toLowerCase().equals(".bmp") ||
suffix.toLowerCase().equals(".png") ||
suffix.toLowerCase().equals(".gif") )
{
list.add(f.getPath());
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
return list;
}
6.擴展功能;後期將介紹實現文件檢索批量上傳圖片,用戶通過Checkbox複選框選擇自己要上傳的圖片(必須是圖片文件纔可上傳,不是圖片給用戶提示信息),將這些選中的圖片可獲取圖片名稱加入到一個list數組保存起來,然後統一上傳。