http://blog.ityao.com/archives/198
最近在帮一个朋友做一个程序,其中用到AIR读取Excel导出的CSV文件进行数据导入数据库的工作,中间碰到了一些问题,最后都可以一一解决,感觉挺有意思,特意拿来个大家分享一下。
完整代码在本贴的最后,完成的效果如下图所示:

具体开发步骤如下
- 第一步,CSV文件格式设置和导出:
通常一些业务资料会保存在Excel当中,CSV可以通过Excel文件的”另存为”获得这个格式的文件,不过要注意的是CSV的分隔符在某些机器上是”,”某些是”;”,这个是通过控制面板(”日期,时间语言和区域设置”->”区域和语言选项”->”自定义”->”列表分隔符” )进行设置的。我的操作系统是XP,用的是Excel 2007,导出的时候是”;”。
可能在别的系统下操作会有所不同,在我的机器上导出的CSV文件是ansi内码。 - 第二步,获得文件的引用:
这里使用了两种不同的方式去获得文件的引用(即选择文件),一种是点击一个按钮,另一种是直接把csv文件拖动到界面上。
点击按钮选择文件更直观写,这部分代码如下:private function browseFile():void{ var typeFilters:Array = new Array(); var typeFilter:FileFilter; typeFilter = new FileFilter("CSV Files(*.csv)", "*.csv"); typeFilters.push(typeFilter); var file:File = new File(); file.addEventListener(Event.SELECT, importData); file.browseForOpen("选择要导入的CSV数据文件",typeFilters); }这里设置了类型过滤器,用户只能选择”csv”结尾的文件,方便在一大堆文件中找出这个文件。
private function importData(e:Event):void{ var file:File = new File(e.target.nativePath); getFileContent(file); }选择具体的文件后就可以读取里面的数据了。
而另外一种方法是把要读取的文件进程序中以完成数据导入,这种方式更直观快捷。
- 第三步,判断文件编码,然后读取文件:
之前刚完成程序后进行测试,csv文件里面有大量的中文内容,一开始没判断代码的时候直接使用下面的语句读取文件:var fileContent:String = fileStream.readUTFBytes(fileStream.bytesAvailable)
后来更发现数据进数据库后会是乱码,才知道这个csv文件不是UTF8的格式,是ANSI的,用notepad另存编码为UTF8就可以正常导入数据了。
追查原因,是因为这个ansi文件是不能正确用UTF的方式去读的。
那么以后怎么自动识别文件内码并正确读取而不变成乱码呢,于是就上搜索引擎搜索,终于找到一篇文章,抄了上面一段自动判断文件编码的代码。一句话概括之–先判断内容编码格式再按照编码格式去读取其数据就没错了!var code:String; switch(true){ case (b1==-1&&b2==-2): code = "unicode"; break; case (b1==-2&&b2==-1): code = "unicodeFFFE"; break; case (b1==-17&&b2==-69): code = "utf-8"; break; default: code = "ansi"; break; } var fileContent:String = fileStream.readMultiByte(fileStream.bytesAvailable,code); fileStream.close(); - 第四步,导入CSV的数据到数据库中:
这一步相对简单,首先是删除数据库已有的数据,然后把上一步中读成字符串的文件内容每行解析成一条数据,然后导入数据库中,这里使用了pimento框架的持久层实现方法,可以很容易地在Actionscript端完成CRUD的操作,代码如下:删除已有数据,和服务器端JAVA EE里JPA的实现代码几乎一样:
private function parseCSV():void{ var query:Query = entityManager.createQuery("DELETE FROM Owner o WHERE o.orgID=:orgID"); query.setNamedParameter("orgID",curOrg.id); query.executeUpdate().addResultHandler(successDeleteOwner); if(owners!=null && owners.length>0){ owners.removeAll(); }else if(owners==null){ owners = new ArrayCollection(); } }然后是拆分CSV的文件,并把记录导入数据库
private function successDeleteOwner(rows:int):void{ var csvArray:Array = new Array(); var csvLines:Array = _content.split(String.fromCharCode(13,10)); csvLines.splice(0,1); for each(var s:String in csvLines){ var lineItems:Array = s.split(","); var owner:Owner = new Owner(); owner.homeNumber = lineItems[3]; owner.orgID = curOrg.id; owner.ownerName = lineItems[1]; owner.propertyID = lineItems[0]; owner.smsNumber = lineItems[2]; owner.remark = lineItems[4]; entityManager.persist(owner).addResultHandler(successCreatedOwner); } }
是不是觉得很有趣呢,在一个flex页面中就完成了一个独立的功能的前后台实现了,希望这个帖子能引起大家对parsley和pimento这两个框架的兴趣,过段时间我会继续写一些相关的介绍。
完整的程序代码如下:
<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
addedToStage="dispatchEvent(new Event('configureIOC', true))" horizontalAlign="center"
width="100%" height="100%" creationComplete="listOrginazation()"
horizontalScrollPolicy="off" verticalScrollPolicy="off"
nativeDragEnter="dragEnterHandler(event)" nativeDragDrop="dragDropHandler(event)">
<mx:Script>
<![CDATA[
import flash.utils.setTimeout;
import org.spicefactory.lib.reflect.types.Void;
import mx.events.ListEvent;
import mx.events.ItemClickEvent;
import org.spicefactory.pimento.service.Query;
import mx.collections.ArrayCollection;
import org.spicefactory.cinnamon.service.ErrorMessage;
import mx.controls.Alert;
import mx.utils.StringUtil;
import com.coralbay.model.Organization;
import com.coralbay.model.Owner;
import org.spicefactory.pimento.service.EntityManager;
[Inject]
public var entityManager:EntityManager;
[Bindable]
private var organizations:ArrayCollection;
[Bindable]
private var curOrg:Organization = null;
[Bindable]
private var curOwner:Owner = null;
[Bindable]
private var owners:ArrayCollection;
private function listOrginazation():void{
var query:Query = entityManager.createQuery("select o from Organization o Order By o.createTime desc");
query.getResultList().addResultHandler(onResult);
}
private function onResult (orgs:Array) : void {
organizations = new ArrayCollection(orgs);
if(orgs.length>0){
curOrg = orgs[0];
orgList.selectedIndex = 0;
}else{
curOrg = null;
}
}
private function changeOrg():void{
curOrg = orgList.selectedItem as Organization;
listowner(curOrg.id);
}
private function listowner(orgId:int):void{
var query:Query = entityManager.createQuery("select o from Owner o WHERE o.orgID=:orgID");
query.setNamedParameter("orgID",orgId);
query.getResultList().addResultHandler(onownerResult);
}
private function onownerResult(ops:Array):void{
owners = new ArrayCollection(ops);
}
private function browseFile():void{
var typeFilters:Array = new Array();
var typeFilter:FileFilter;
typeFilter = new FileFilter("CSV Files(*.csv)", "*.csv");
typeFilters.push(typeFilter);
var file:File = new File();
file.addEventListener(Event.SELECT, importData);
file.browseForOpen("选择要导入的CSV数据文件",typeFilters);
}
private function importData(e:Event):void{
//Alert.show(e.target.nativePath);
var file:File = new File(e.target.nativePath);
getFileContent(file);
}
private function dragEnterHandler(evt:NativeDragEvent):void{
if(evt.clipboard.hasFormat(ClipboardFormats.FILE_LIST_FORMAT)){
var dropFiles:Array = evt.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
if(dropFiles.length>1){
Alert.show("只能选择一份CSV文件");
return;
}
var file:File = dropFiles[0] as File;
if(file.extension == "csv"){
NativeDragManager.acceptDragDrop(this);
}
}
}
private function dragDropHandler(evt:NativeDragEvent):void{
//Alert.show("hihi");
NativeDragManager.dropAction = NativeDragActions.COPY;
var dropFiles:Array = evt.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
getFileContent(dropFiles[0]);
}
private var _content:String;
private function getFileContent(_file:File):void{
var fileStream:FileStream = new FileStream();
fileStream.open(_file, FileMode.READ);
var b1:int = fileStream.readByte();
var b2:int = fileStream.readByte();
fileStream.position = 0;
var code:String;
switch(true)
{
case (b1==-1&&b2==-2):
code = "unicode";
break;
case (b1==-2&&b2==-1):
code = "unicodeFFFE";
break;
case (b1==-17&&b2==-69):
code = "utf-8";
break;
default:
code = "ansi";
break;
}
//var fileContent:String = fileStream.readUTFBytes(fileStream.bytesAvailable);
var fileContent:String = fileStream.readMultiByte(fileStream.bytesAvailable,code);
fileStream.close();
_content = fileContent;
parseCSV();
}
private function onErrorResult(event:ErrorMessage):void{
Alert("删除数据失败!");
listowner(curOrg.id);
}
private function parseCSV():void{
var query:Query = entityManager.createQuery("DELETE FROM Owner o WHERE o.orgID=:orgID");
query.setNamedParameter("orgID",curOrg.id);
query.executeUpdate().addResultHandler(successDeleteOwner);
if(owners!=null && owners.length>0){
owners.removeAll();
}else if(owners==null){
owners = new ArrayCollection();
}
}
private function successDeleteOwner(rows:int):void{
var csvArray:Array = new Array();
var csvLines:Array = _content.split(String.fromCharCode(13,10));
csvLines.splice(0,1);
for each(var s:String in csvLines){
var lineItems:Array = s.split(",");
var owner:Owner = new Owner();
owner.homeNumber = lineItems[3];
owner.orgID = curOrg.id;
owner.ownerName = lineItems[1];
owner.propertyID = lineItems[0];
owner.smsNumber = lineItems[2];
owner.remark = lineItems[4];
entityManager.persist(owner).addResultHandler(successCreatedOwner);
}
}
private function successCreatedOwner(owner:Owner):void{
//nothing to do now
owners.addItem(owner);
}
]]>
</mx:Script>
<mx:HBox width="100%" verticalAlign="middle">
<mx:Label text="选择公司:"/>
<mx:ComboBox id="orgList" dataProvider="{organizations}" labelField="name" close="changeOrg()"/>
<mx:Spacer width="100%"/>
<mx:Button label="清空当前数据并导入新业主资料" click="browseFile()"/>
</mx:HBox>
<mx:DataGrid width="100%" dataProvider="{owners}" height="100%" id="ownerDG">
<mx:columns>
<mx:DataGridColumn dataField="propertyID" headerText="房号"/>
<mx:DataGridColumn dataField="ownerName" headerText="业主姓名"/>
<mx:DataGridColumn dataField="smsNumber" headerText="短信号码"/>
<mx:DataGridColumn dataField="homeNumber" headerText="住宅电话"/>
<mx:DataGridColumn dataField="remark" headerText="备注"/>
</mx:columns>
</mx:DataGrid>
</mx:VBox>
7 条评论
没怎么用到CSV..读读看..
支持阿淫 顶一下
很好,很强大
阿淫,你应该再弄一个parsley和pimento这两个框架和教程
呵呵,会的
这两个框架早就check下来了,一直没细看过,期待阿淫的教程…
帮助相当大