Tuesday, September 15, 2009

html向flash传参数

如果想在网页中嵌入flash,可以通过一下代码来实现:
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0" width="800" height="600">
<param name="movie" value="main.swf" />
<param name="quality" value="high" />
<embed src="main.swf" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="800" height="600"></embed>
</object>

标红的是文件名,上面的例子是跟html文件在同目录下的,也可以不在同目录。上面的代码将调用main.swf这个flash文件。

但是我的main.swf里面用actionscript定义了两个变量,需要通过html传递两个值给main.swf,然后显示不同的内容。

在<param name="movie" value="main.swf" />后面加入一行代码<param name="flashVars" value="pic=5&word=2" />,可以将pic和word这两个变量传到flash里面,在flash中的actionscript中通过_root.pic 和 _root.word 可以得到这两个变量的值。

测试,IE下成功,firefox下失败。

经过网上查找资料,发现IE是读param标签中name为flashVar的值,但是firefox是读embed标签的值,所以应该把 flashVars="pic=5&word=2" 这段代码加到embed标签末尾,即:
<embed src="main.swf" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="800" height="600" flashVars="pic=5&word=2"></embed>

ok,IE&firefox都成功。

html向flash传参数

转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://crazyrabbit.blogbus.com/logs/30667726.html

我们都知道在dw中插入flash,dw会用几种方式插入保证swf在各种浏览器中正常运行,当然这都是dw自动完成的,不劳我们动手,但是要传递参数时就要靠我们自己了,要如何传递才能保证兼容性问题呢


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<script src="Scripts/AC_RunActiveContent.js" type="text/javascript"></script>
</head>

<body>
<script type="text/javascript">
AC_FL_RunContent( 'codebase','http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,28,0',
'width','500','height','300','flashvars','data=xml/index.xml','src','swf/Currencyshow','quality','high','pluginspage','http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash','movie','swf/Currencyshow' ); //end AC code
</script><noscript><object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,28,0" width="500" height="300">
<param name="movie" value="swf/Currencyshow.swf?data=xml/index.xml" />
<param name="quality" value="high" />
<embed src="swf/Currencyshow.swf?data=xml/index.xml" quality="high" pluginspage="http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash" type="application/x-shockwave-flash" width="500" height="300"></embed>
</object></noscript>
</body>
</html>

只要保证这几个地方参数一样即可顺利通过啦



一片参考转自 http://www2.flash8.net/teach/6942.htm



先来看看flash自动生成的网页是如何插入flash文件的:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh_cn" lang="zh_cn">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>test</title>
<script language="javascript">AC_FL_RunContent = 0;</script>
<script src="AC_RunActiveContent.js" language="javascript"></script>
<style type="text/css">
<!--
body {
background-color: #999900;
}
-->
</style></head>
<body>
<!--影片中使用的 URL-->
<!--影片中使用的文本-->
<!--
eee
-->
<!-- saved from url=(0013)about:internet -->
<script language="javascript">
if (AC_FL_RunContent == 0) {
alert("此页需要 AC_RunActiveContent.js");
} else {
AC_FL_RunContent(
'codebase', 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0',
'width', '550',
'height', '400',
'src', 'test',
'quality', 'high',
'pluginspage', 'http://www.macromedia.com/go/getflashplayer',
'align', 'middle',
'play', 'true',
'loop', 'true',
'scale', 'showall',
'wmode', 'transparent',
'devicefont', 'false',
'id', 'test',
'bgcolor', '#666666',
'name', 'test',
'menu', 'true',
'allowFullScreen', 'false',
'allowscriptAccess','sameDomain',
'flashvars','txt=wwwww',
'movie', 'test',
'salign', ''
); //end AC code
}
function sendvar(){
test.style.height=500;
test.SetVariable("mv","kkkkkk")
}
</script>
<noscript>
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="550" height="400" id="test" align="middle">
<param name="allowscriptAccess" value="sameDomain" />
<param name="allowFullScreen" value="false" />
<param name="movie" value="test.swf" /><param name="quality" value="high" /><param name="bgcolor" value="#666666" /><embed src="test.swf" quality="high" bgcolor="#666666" width="550" height="400" name="test" align="middle" allowscriptAccess="sameDomain" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
</object>
</noscript>
<br>
<label>xxx
<input type="submit" name="Submit" value="提交" onClick="sendvar()">
</label>

</body>
</html>
这个网页插入flash共使用了3种方式,应对各种情况,尽可能使swf文件在各种情况、各种浏览器中都能够正常显示运行。

先来看看第一种情况:
最开始使用javascript插入swf文件,这种方式兼容性最好,可以同时兼容IE内核的浏览器及FireFox 浏览器,而且这种插入方式可以避免IE中控件激活框的出现,非常实用。这段自动生成的代码包含的内容很丰富,你可以在其中任意添加IE或者其他浏览器使用的参数,例如:
'name', 'test',
'id', 'test',
这个是javascript引用swf文件的变量名,使javascrit可以直接对该swf文件进行操作,其中IE只使用id变量就可以了,name变量是针对embed插入方式FireFox使用的。

虽然javascript的插入方式优点多多,但是一旦用户禁用了javascript,就不行了。下面说说第二种方式:
删除所有的javascript代码(同时删除<noscript>和</noscript>)。
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="550" height="400" id="test" align="middle">
<param name="allowscriptAccess" value="sameDomain" />
<param name="allowFullScreen" value="false" />
<param name="movie" value="test.swf" /><param name="quality" value="high" /><param name="bgcolor" value="#666666" />
这是IE使用的flash文件插入方式,如果只使用了这段代码,IE可以正常显示,但是FireFox就不能显示了。

第三种,embed插入方式
<embed src="test.swf" quality="high" bgcolor="#666666" width="550" height="400" name="test" align="middle" allowscriptAccess="sameDomain" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
这种方式IE和FireFox都可以正常显示

第二种和第三种的参数解释可以参考下面的文章
http://space.flash8.net/space/?246908/action_viewspace_itemid_408019.html

就算不使用javascript,后面两种flash插入方式也可以通过htm页面向flash传递变量:

1、object插入方式:
增加参数:<param name="flashvars" value="mv=hello!">

2、embed插入方式:
在后面加入: flashvars="mv=hello!"

通过以上两种方式,flash都可以收到一个变量名为“mv”的变量,内容为“hello!" 。

Sunday, September 13, 2009

flash与数据库的连接

确切地说..flash是不可以直接与数据库连接的.只能是通过ASP(只是我比较了解ASP,也可以是其他的PHP/JSP等);
所以呢.首先,先在ASP里编写好连接数据库的语句
<%
dim cn
dim connstr
dim db
db="asp.mdb"
Set cn = Server.CreateObject("ADODB.Connection")
connstr="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath(""&db&"")
cn.Open connstr
%>
存储为cn.asp文件;
第二步;就编写一个读取数据库数据的ASP文件喽...
<!--#include file="cn.asp"-->
<%
set rs=server.createobject("adodb.recordset")
rs.open "select * from class ",cn,3,3
for i=1 to rs.recordcount
if not rs.eof then
totalClass=totalClass&rs("Class")&","
totalLink=totalLink&rs("classlink")&","
rs.movenext()
end if
next
response.write ("flashClass="&totalClass&"&")
response.write ("flashLink="&totalLink&"&")
'注意这个写格式.多个参数得用&这个来连接.有些人会忽略到这一点.导致在flash不能写出数据来.
%> 将这个文件存储为:write.asp
第三步;回到flash那里来编写语句.把write.asp文件加载进来.
第一帧:
System.useCodepage=true;
var newload = new LoadVars();//如果不是很了解这个LoaVars,可以去查一下那个flash里面的帮助文档
newload.load("write.asp");
newload.onLoad = function(success) {
if (success) {
_root.gotoAndStop(2);//当文件被加载完成后,执行第二帧.
}
};
stop();//这里要注意.如果不用停止.假设文件还没有加载完就执行第二帧...而在第二帧是在flash里读取数据的.那就导致读不出数据
第二帧:
_root.name.text = newload.flashClass;//下面两句是读取数据的.
_root.link.text = newload.flashLink;
_root.bt._visible = false;//是一个影片的名字,里面放有一个动态文本bttext
//现在就把数据放到数组中去....
var aspclass = newload.flashClass;
var link = newload.flashLink;
var Aclass = new Array();
var Blink = new Array();
for (i=0; i<aspclass.length; i++) {
Aclass = aspclass.split(",", i);
Blink = link.split(",", i);
}
for (i=0; i<Aclass.length-1; i++) {
//for (i=1; i<6; i++) {
_root.bt.duplicateMovieClip("bt"+i, i);
_root["bt"+i]._y = i*30;
_root["bt"+i]._x = 5;
_root["bt"+i].url = Blink;
_root["bt"+i].bttext.text = Aclass;
_root["bt"+i].onRelease = function() {
_root.link2.text = this.url;
getURL("http://"+this.url,"_blank");
};
}

Flash与数据库的集成

本文解释如何连接flash到一个Access数据库,flash是不能直接与数据库交换信息的,我们必须借助asp(或其它服务器端的脚本语言)。ASP可以访问数据库,并可将信息传递给FLASH。下面我将建立一个简单的flash地址簿来演示这一过程。
注:要完成本教程您的PC上需要有
1、 flash 5(或 flash mx )
2、 (Internet information Services 4.0(或IIS5.0)
3、 Microsoft Access
一、预备知识:
flash中的脚本命令:
loadVariables(url,location);
通过loadvariable方法可以实现与ASP传递信息。

Loadvariables命令从URL所指的文件内容中获得信息,并将这些信息赋给FLASH中的变量。

其中URL所指的文件内容必须为MIME格式或者为URL格式编码的格式。
例如:URL所指定的页包含如下内容:
Var1=Test&Var2=Demo

Flash中变量Var1的值被赋予“test”,Var2的值被赋予“Demo”。
二、数据库设计:
建立只包含一个表:Contacts的数据库addressbook.mdb。Contacts表的结构如下:
Field nameype Size
ContactID AutoNumber -
Name Text 50
Telephone Text 50
City Text 50
Notes Memo -
三、asp设计:
用编辑软件制作名为:getdetails.asp
getdetails.asp代码如下:
<%
Set DataConn = Server.CreateObject("ADODB.Connection")
DataConn.Open "Driver=Microsoft Access Driver (*.mdb);DBQ=" &
Server.MapPath("AddressBook.mdb")

Set cmdTemp = Server.CreateObject("ADODB.Command")
Set rstContacts = Server.CreateObject("ADODB.Recordset")

cmdTemp.CommandText = "Select * From Contacts"
cmdTemp.CommandType = 1
Set cmdTemp.ActiveConnection = DataConn

rstContacts.Open cmdTemp, , 1, 3

rstContacts.Move CLng(Request("Record"))

Response.write "Name=" & Server.URLEncode(rstContacts("Name")) & "&"
Response.write "Telephone=" & Server.URLEncode(rstContacts("Telephone")) & "&"
Response.write "City=" & Server.URLEncode(rstContacts("City")) & "&"
Response.write "Notes=" & Server.URLEncode(rstContacts("Notes")) & "&"
Response.write "TotalRecords=" & rstContacts.RecordCount

rstContacts.Close
DataConn.Close
%>

在浏览器中查看getdetails.asp?record=2,结果如下:

Name=Steve+Tipson&Telephone=%2B44+2123+121+1245&City=Birmingham&Notes=Artist+in+waiting%2E&TotalRecords=4

四、flash设计
1、在flash中建立一个名为AddressBook的movie clip,用于地址簿,它包含五个动态文本框用于显示数据库信息,两个按钮(一个左箭头、一个右箭头)用于数据库记录导航,此MC大致如下图如示:
左箭头上的Actionscript为:
on (release)
{
CurrentRecord--;
if (CurrentRecord == -1)
CurrentRecord = TotalRecords-1;
loadVariables ("getdetails.asp?Record=" add String(CurrentRecord), this);
}

右箭头上的Actionscript为:

on (release)
{
CurrentRecord++;
if (CurrentRecord == TotalRecords)
CurrentRecord = 0;

loadVariables ("getdetails.asp?Record=" add String(CurrentRecord), this);
}

2、将movie clip“ AddressBook”放入主场景中。
在MC上加actionscript为:

onClipEvent(data)
{
strName = Name;
strTelephone = Telephone;
strCity = City;
strNotes = Notes;
strPosition = "Record " add String(CurrentRecord+1) add " of " add String(TotalRecords);
}

onClipEvent(load)
{
CurrentRecord = 0;
loadVariables ("getdetails.asp?Record=0", this);

}

整个制作过程结束,你可以测试你的flash了!

Falsh access database

下面重点将三种flash请求和接收数据的方法

一、loadVariables

loadVariables(url:String, target:Object, [method:String]) : Void

url:服务端地址。

target:指向接收所加载变量的影片剪辑的目标路径。

method: [可选] - 指定用于发送变量的 HTTP 方法。该参数必须是字符串 GET或 POST。GET方法将变量附加到 URL 的末尾,它用于发送少量的变量。POST方法在单独的 HTTP 标头中发送变量,它用于发送长字符串的变量。

例:一个简单的flash与数据库交互的例子,当鼠标移动到按钮上时,在鼠标旁边以文本框的形式显示按钮的信息(按钮的信息在数据库中存储)。

Flash端请求数据代码:
function ShowInfo()
{
loadVariables("http://10.72.25.203/flashy/FlashService.aspx", _root, "POST");
hezuo_btn.label = "";
}

这样将根影片剪辑上的所有变量发送给了一个aspx服务,并指定用根影片剪辑_root,来接收服务端返回的数据,这样适合变量较少的情况,因为这中方法是将根影片剪辑上的所有变量都发送到了服务端,如果想有选择的对变量进行发送,可用http://10.72.25.203/flashy/FlashService.aspx?变量名1=变量1值&变量名2=变量2值 这种方式来发送。

Flash端接收服务端返回数据的代码:

_root.onData = function()
{
_root.createTextField("textV",3,this._xmouse-50,this._ymouse-50,100,35);
textV.border = true;
textV.borderColor = 0x33BDCC;
textV.background = true;
textV.backgroundColor = 0x33BDCC;
textV._alpha = 40;
textV.multiline = true;
textV.wordWrap = true;
textV.text = you;
};

用根影片剪辑的onData事件接收,并将接收到的数据(存储在变量you中)用文本域的形式显示。

Flash按钮事件和发送变量的定义代码:

var zhan_name:String;
play1_btn.onRollOver = function(){
zhan_name = "合作";
ShowInfo();
}
play2_btn.onRollOver = function(){
zhan_name = "百口泉";
ShowInfo();
}
play3_btn.onRollOver = function(){
zhan_name = "重油";
ShowInfo();
}

注意代码写完后在发布设置中将本地回放安全性设为:只访问网络(后面的例子全部做相同的设置)。


服务端接收代码:

Request.Form["zhan_name"];

注意如果用URL?Par1=Value1&Par2=Value2这种方式发送请求,接收代码应写为:
Request.QueryString["zhan_name "];

服务端返回给flash数据的代码:

Response.Write("you=返回的数据数据");

服务端完整代码:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data.OracleClient;

public partial class _Default : System.Web.UI.Page
{
OracleConnection OraCnn;
OracleCommand OC;
OracleDataAdapter OA;
protected void Page_Load(object sender, EventArgs e)
{
OraCnn = new OracleConnection(GetDataInfo());
}

private string GetDataInfo()
{
OracleConnectionStringBuilder OS = new OracleConnectionStringBuilder();
OS.UserID = "sdptest";
OS.Password = "sdptest";
OS.DataSource = "ORA116";
return OS.ConnectionString;
}

public void GetDataFromtoreProcedure()
{
Response.Write("you=");
OraCnn.Open();
OC = new OracleCommand("oilstore.oilstore", OraCnn);
OC.CommandType = CommandType.StoredProcedure;
OracleParameter OracleP1 = new OracleParameter("ZName", OracleType.VarChar, 10);
OracleP1.Direction = ParameterDirection.Input;
OracleP1.Value = Request.Form["zhan_name"];
OracleParameter OracleP2 = new OracleParameter("C", OracleType.Cursor);
OracleP2.Direction = ParameterDirection.Output;
OC.Parameters.Add(OracleP1);
OC.Parameters.Add(OracleP2);
OA = new OracleDataAdapter(OC);
DataTable DT = new DataTable();
OA.Fill(DT);
OraCnn.Close();
if (DT.Rows.Count > 0)
{
string curyou = string.Empty;
for (int i = 0; i < DT.Rows.Count; i++)
{
for (int j = 0; j < DT.Columns.Count; j++)
{
curyou += DT.Rows[i][j] + " ";
}
}
Response.Write(curyou);
}
else
{
Response.Write("无数据!");
}
}

}

服务端接收到变量zhan_name后,通过Oracle存储过程取数据,然后返回,注意返回形式:Response.Write("you="),将返回的结果集赋给了变量you,flash端可以接收到you的值,注意这种方式一次只能够返回一个变量,如果这样写:Response.Write("you=132,qi=234"),这样flash是读不出qi的,读出you的值是:132,qi=234。


Flash+PHP+mySQL

Flash的部分与ASP的部分一样, 只是把当中的后台文件名更改一下



function loadData() {
loader = new LoadVars();
loader.load("server.php?time="+new Date().getTime()); //向ASP取得资料的连接, 这里我不使用Math.random是因为这样有个缺点
loader.onLoad = function(success) {
if (success) {
display.htmlText = loader.Result; //loader.Result是ASP传递回来的资料
} };
} submit.onRelease = function() { //当按钮按下放开的时候
if (name.text.length == 0) { //这里是判断输入框是否为空
Selection.setFocus(name); //把光标设定在指定的输入框
} else if (msg.text.length == 0) { //同上
Selection.setFocus(msg);
} else {
status.text = ""; //这个动态文本你们可以自己设定
sender = new LoadVars();
sender.onLoad = function(success) {
if (success) {
if (sender.Result == "Success" ) { //传递回来的讯息为Success时
status.text = "记录成功...";
name.text = msg.text=""; //清空输入栏位
loadData(); //重新刷新资料
} else {
status.text = "记录失败, 请再次尝试...";
} delete sender; //养成习惯把LoadVars变量删除以释放内存空间
} };
sender.load("server.php?action=save&name="+name.text+"&msg="+msg.text, sender, "POST" );//和sendAndLoad的功用一样, 传送出变量并等待资料传回, 传回的资料会在onLoad中截取
} };
loadData(); //在一开始载入资料库中的资料

PHP部分 :



<?php
$DBhost = "localhost"; // 服务器的DNS名
$DBuser = "root"; // 用户名
$DBpass = ""; // 用户密码
$DBName = "super-tomato"; //资料库名字
$table = "guestbook"; // 资料库中资料表的名字

$DBConn = mysql_connect($DBhost,$DBuser,$DBpass) or die("無法連接資料庫 : " . mysql_error()); //开始连接mysql

mysql_select_db($DBName, $DBConn) or die("無法連接資料庫: " . mysql_error()); //选择mysql資料库并连接

if($action == "save" ) { //当Flash的action变量为save时
$sql = "INSERT INTO ".$table."(Name, Message) VALUES ('".$name."', '".$msg."')"; // 把资料写入资料表内
$insert = mysql_query($sql, $DBConn) or die("無法連接資料庫: " . mysql_error());
if($insert) { //资料写入成功
echo "&Result=Success";
} else {
echo "&Result=Fail";
} } else {
$sql = "SELECT * FROM ".$table; //取得资料表中所有的资料
$query = mysql_query($sql, $DBConn) or die("無法選取資料 : " . mysql_error());
while ($array = mysql_fetch_array($query)) { //循环取得每一笔资料
$strName = mysql_result($query, $i, "Name" );
$strMsg = mysql_result($query, $i, "Message" );
$record .= $strName." : ".$strMsg."<br>"; //把资料储存在变量当中
$i++;
} echo "&Result=".$record."<br><b>Finish</b>"; //传递变量中的资料到Flash
}

mysql_close(); //结束资料库连接
?>

******** PHP 连接 Microsoft Access 的方法 **********



<?
$db = "./Database.mdb";

$conn = new COM("ADODB.Connection" ); //在PHP使用COM来连接

// 两种方法都可以连接选一种即可
$conn->Open("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=$db" );
//$conn- > Open("DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=$db" );

$sql = "SELECT * FROM guestbook";
$rs = $conn- > Execute($sql);
?>

Thursday, September 10, 2009

java文件操作

java.io
---------------------------------------------------------------



package common;

import java.io.*;

public class FileOperate {
public FileOperate() {
}


public void newFolder(String folderPath) {
try {
String filePath = folderPath;
filePath = filePath.toString();
java.io.File myFilePath = new java.io.File(filePath);
if (!myFilePath.exists()) {
myFilePath.mkdir();
}
}
catch (Exception e) {
System.out.println("新建目录操作出错");
e.printStackTrace();
}
}


public void newFile(String filePathAndName, String fileContent) {

try {
String filePath = filePathAndName;
filePath = filePath.toString();
File myFilePath = new File(filePath);
if (!myFilePath.exists()) {
myFilePath.createNewFile();
}
FileWriter resultFile = new FileWriter(myFilePath);
PrintWriter myFile = new PrintWriter(resultFile);
String strContent = fileContent;
myFile.println(strContent);
resultFile.close();

}
catch (Exception e) {
System.out.println("新建目录操作出错");
e.printStackTrace();

}

}


public void delFile(String filePathAndName) {
try {
String filePath = filePathAndName;
filePath = filePath.toString();
java.io.File myDelFile = new java.io.File(filePath);
myDelFile.delete();

}
catch (Exception e) {
System.out.println("删除文件操作出错");
e.printStackTrace();

}

}


public void delFolder(String folderPath) {
try {
delAllFile(folderPath); //删除完里面所有内容
String filePath = folderPath;
filePath = filePath.toString();
java.io.File myFilePath = new java.io.File(filePath);
myFilePath.delete(); //删除空文件夹

}
catch (Exception e) {
System.out.println("删除文件夹操作出错");
e.printStackTrace();

}

}


public void delAllFile(String path) {
File file = new File(path);
if (!file.exists()) {
return;
}
if (!file.isDirectory()) {
return;
}
String[] tempList = file.list();
File temp = null;
for (int i = 0; i < tempList.length; i++) {
if (path.endsWith(File.separator)) {
temp = new File(path + tempList[i]);
}
else {
temp = new File(path + File.separator + tempList[i]);
}
if (temp.isFile()) {
temp.delete();
}
if (temp.isDirectory()) {
delAllFile(path+"/"+ tempList[i]);//先删除文件夹里面的文件
delFolder(path+"/"+ tempList[i]);//再删除空文件夹
}
}
}


public void copyFile(String oldPath, String newPath) {
try {
int bytesum = 0;
int byteread = 0;
File oldfile = new File(oldPath);
if (oldfile.exists()) { //文件存在时
InputStream inStream = new FileInputStream(oldPath); //读入原文件
FileOutputStream fs = new FileOutputStream(newPath);
byte[] buffer = new byte[1444];
int length;
while ( (byteread = inStream.read(buffer)) != -1) {
bytesum += byteread; //字节数 文件大小
System.out.println(bytesum);
fs.write(buffer, 0, byteread);
}
inStream.close();
}
}
catch (Exception e) {
System.out.println("复制单个文件操作出错");
e.printStackTrace();

}

}


public void copyFolder(String oldPath, String newPath) {

try {
(new File(newPath)).mkdirs(); //如果文件夹不存在 则建立新文件夹
File a=new File(oldPath);
String[] file=a.list();
File temp=null;
for (int i = 0; i < file.length; i++) {
if(oldPath.endsWith(File.separator)){
temp=new File(oldPath+file[i]);
}
else{
temp=new File(oldPath+File.separator+file[i]);
}

if(temp.isFile()){
FileInputStream input = new FileInputStream(temp);
FileOutputStream output = new FileOutputStream(newPath + "/" +
(temp.getName()).toString());
byte[] b = new byte[1024 * 5];
int len;
while ( (len = input.read(b)) != -1) {
output.write(b, 0, len);
}
output.flush();
output.close();
input.close();
}
if(temp.isDirectory()){//如果是子文件夹
copyFolder(oldPath+"/"+file[i],newPath+"/"+file[i]);
}
}
}
catch (Exception e) {
System.out.println("复制整个文件夹内容操作出错");
e.printStackTrace();

}

}


public void moveFile(String oldPath, String newPath) {
copyFile(oldPath, newPath);
delFile(oldPath);

}


public void moveFolder(String oldPath, String newPath) {
copyFolder(oldPath, newPath);
delFolder(oldPath);

}
}

Tuesday, August 4, 2009

Java UTF–8 international character support with Tomcat and Oracle

Introduction I've spent the last few days looking at getting proper international character support working in our Files.Warwick application working.
At E-Lab we've never been that great at doing internationalisation support. BlogBuilder does a pretty good job of internationalisation as can be seen by quite a lot of our bloggers writing in Chinese/Korean/Japanese.
However, it's a bit of a cludge and doesn't work everywhere.
It didn't take long for someone to upload a file to Files.Warwick with an "é" in the file name. Due to our previous lack of thought in this area, this swiftly turned into a ? :(
So...how do you get your app to support international characters throughout?
What is international character support?You'll hear all sorts of jargon regarding internationalisation support. Here is a little explanation of what it is all about.
What I do NOT mean is i18n support which is making the application support multiple languages in the interface so that you can read help pages and admin links in French or Chinese. What I mean by internationalisation support is being able to accept user input in any language or character set.
Tim Bray has a really good explanation of some of the issues surrounding ASCII/Unicode/UTF-8.
UTF-8 all the way through the stackWe need to look at UTF-8 support in the following areas:
URLs Apache
HTML
Javascript POST data
File download (Content-Disposition)
JSPs Java code Tomcat Oracle File system I'll go through each of these areas and explain how well they are supported by default and what changes you might need to make to support UTF-8 in each area.
URLs URLs should only contain ASCII characters. The ASCII character set is quite restrictive if you want to use Chinese characters for instance, so there is some encoding needed here. So if you've got a file with a Chinese character and you want to link to it, you need to do this:
"中.doc" -$gt "%E4%B8%AD.doc"
Thankfully this can be done with a bit of Java:
java.net.URLEncoder.encode("中.doc","UTF-8");
So, whenever you need to generate something for the address bar or a direct or something like that, you must URL encode the data. You don't have to detect this as it doesn't hurt to do this for links which are just plain old ASCII as they don't get changed, as you can see with the ".doc" ending on the above example.
ApacheGenerally you don't need to worry about Apache as it shouldn't be messing with your HMTL or URLs. However, if you are doing some proxying with mod_proxy then you might need to have a think about this. We use mod_proxy to do proxying from Apache through to Tomcat. If you've got encoded characters in URL that you need to convert into some query string for your underlying app then you're going to have a strange little problem.
If you have a URL coming into Apache that looks like this:
http://mydomain/%E4%B8%AD.doc and you have a mod_rewrite/proxy rule like this:
RewriteRule ^/(.*) http://mydomain:8080/filedownload/?filename=$1 [QSA,L,P]
Unfortunately the $1 is going to get mangled during the rewrite. QSA (QueryStringAppend) actually deals with these characters just fine and will send this through untouched, but when you grab a bit of the URL such as my $1 here then the characters get mangled as Apache tries to do some unescaping of its own into ISO-8859-1, but it's UTF-8 not ISO-8859-1 so it doesn't work properly. So, to keep our special characters in UTF-8, we'll escape it back again.
RewriteMap escape int:escapeRewriteRule ^/(.*) http://mydomain:8080/filedownload/?filename=${escape:$1} [QSA,L,P]
Take a look at your rewrite logs to see if this is working.
HTML HTML support for UTF-8 is good, you just need to make sure you set the character encoding properly on your pages. This should be as simple as bit of code in the HEAD of your page:
$ltmeta http-equiv="Content-Type" content="text/html; charset=utf-8"$gt
You should be able to write out UTF-8 characters for real into the page without any special encoding.
Javascript Javascript supports UTF-8 characters very well so as long as you don't use escape() then when your users enter characters, they shouldn't get mangled. We also use AJAX do do some functions in our application so you need to think about that as well but again, it should just work.
All of the above only holds true if you set the character encoding right on your surrounding HTML.
POST data
Getting POST datafrom the user in the right format is simple too. As long as your HTML has the right encoding then you should be ok.
File download (Content-Disposition) If you want to serve files for download from your app, as we obviously do with Files.Warwick then you'll need to understand how browsers deal with non ASCII characters in file names when downloading. Unfortunately the standard is not exactly well defined as no one really thought about UTF-8 file names until recently.
Internet Explorer supports URL encoded file names but Firefox supports a rather strange Base64 encoded value for high byte file names, so something like this should do the job:

String userAgent = request.getHeader("User-Agent");String encodedFileName = null;
if (userAgent.contains("MSIE") userAgent.contains("Opera")) { encodedFileName = URLEncoder.encode(node.getName(), "UTF-8");} else { encodedFileName = "=?UTF-8?B?" + new String(Base64.encodeBase64(node.getName().getBytes("UTF-8")), "UTF-8") + "?=";}
response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"");
Obviously you can tweak the user agent detection to be a bit smarter than this.
JSPs UTF-8 support in JSPs is pretty much a one liner.
$lt%@ page language="java" pageEncoding="utf-8" contentType="text/html;charset=utf-8" %$gt
Include that at the top of every single JSP perhaps in a prelude.jsp file and you're away.
Java codeAs long as you source strings are properly encoded then generally you can rely on Java to keep your UTF-8 encoded input. However, be careful what String functions you perform on your UTF-8 data. Be sure to do things like this:
myStr.getBytes("UTF-8") rather than just myStr.getBytes()
If you don't then you'll most likely end up with ISO-8859-1 bytes instead. If for some reason you can not get your input data to be UTF-8, and it is coming in with a different encoding, you could do something like this to convert it to UTF-8:
String myUTF8 = new String(my8859.getBytes("ISO-8859-1"),"UTF-8")
Debugging can be fun with high byte characters as generally logging to a console isn't going to show you the characters you are expecting. If you did this:
System.out.println(new String(new byte[] { -28, -72, -83},"UTF-8")
Then you'd probably just see a ? rather than the Chinese character that it really should be. However, you can make log4j log UTF-8 messages. Just add
$ltparam name="Encoding" value="UTF-8"/$gt
To the appender in your log4j.xml config. Or this:
log4j.appender.myappender.Encoding=UTF-8
To your log4j.properties file. You might still only see the UTF-8 data properly if you view the log file in an editor/viewer that can view UTF-8 data (Windows notepad is ok for instance).
TomcatBy default Tomcat will encode everything in ISO-8859-1. You can in theory override this by setting the incoming encoding of the HttpServletRequest to be UTF-8, but once some of the request is read, then the encoding is set, so chances are you might not be able to manually do:
request.setCharacterEncoding("UTF-8")
early enough to have an effect. So instead you can tell Tomcat you want it to run in UTF-8 mode by default. Just add the following to the Connector you want UTF-8 on in your server.xml config file in Tomcat.
URIEncoding="UTF-8"
Not doing this has the fun quirk that if you have a request like this:
/test.htm?highByte=%E4%B8%AD
If you did request.getQueryString() you'd get the raw String that "highByte=%E4%B8%AD", but if you did request.getParameter("highByte") then you'd get the ISO-8859-1 encoded value instead which would not be right. Sigh.
OracleYou could just URL encode all of your data and put it into the database in ASCII like you always used to. However, that doesn't make for very readable data. There are two options here although I've only tried the one.
Set the default character encoding of your Oracle database to be UTF-8. However, it is set on a per server basis, not a per schema basis so your whole server would be affected. Use NVARCHAR2 fields instead of VARCHAR2 fields and you can store real UTF-8 data. We went for option 2 as we have a shared Oracle server. First of all, convert all fields that you want to store UTF-8 data in from VARCHAR2s to NVARCHAR2s. Be careful as I don't think you can change back!
You then need to tell your JDBC code somehow that it needs to send data that the NVARCHAR2 fields can undertand. There are a couple of ways of doing this too:
Set the defaultNChar property on the connection to true. Use the setFormOfUse() method that is an Oracle specific extension to the PrepearedStatement I went for option 1 as the problem with option 2 is that you have to somehow get at the Oracle specific connection or prepared statement within your Java code. This is not fun as you'll often be using a connection pool that will hide away these details.
Files system File system support of UTF-8 characters is again pretty good, but you are sometimes going to have issues with viewing the file listings. I just couldn't get a UTF-8 file name to display properly over a putty SSH connection. Through a simple Java test program, I could write and read back a UTF-8 file name on our Solaris 10 box, but all I could ever actually read when doing an "ls" was ?????.doc. So for the sake of maintainability of the file system I went for a URL encoded version of the file. This isn't ideal, but it works.
Conclusion As you can see, there is quite a lot of work involved in supporting UTF-8 throughout. A lot of my time was spent researching as my understanding of encoding issues wasn't great. Now that I've put together this guide, I hope all of our apps can start to work towards full UTF-8 support.
Of course the above guide is quite specific to my experience in the app I was dealing with and the environment I work in so your experiences might be more or less painful :)