GONE WITH THE WIND

--tomorrow is another day

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  30 随笔 :: 19 文章 :: 0 评论 :: 0 Trackbacks

#

1.作用的范围不同:

1)inverse :<set/>,<map/>,<list/>,<array/>,<bag/>

2)cascade :<many-to-one>,<one-to-one/>,<set/>,<map/>,<list/>,<array/>,<bag/>.

2.执行策略不同

1)inverse :首先判断集合的变化情况,然后针对变化执行相应的处理。

2)cascade :直接对集合中的每个元素执行相应的处理。

3.执行的时机不同

1)inverse :在执行SQL语句之前判断是否要执行该SQL语句。

2)cascade :在主控方发生操作时用来判断是否进行级联操作。

4.执行的目标不同

1)inverse :对于<one-to-many>处理被管理表,<many-to-many/>处理中间表。

2)cascade :都只只对被关联表。

总结:书上说了inverse 一对多的时候最好把多的一方设置成false由一的一方来控制;cascade尽量别使,进行显示的添加删除。

posted @ 2009-03-30 16:46 张永耀 阅读(172) | 评论 (0)编辑 收藏

构造这样一个例子,在测试过程中来说明一些Hibernate的高级配置及其相关机制:
有三个类:Category.java,Prodcuct.java,ConfigurationTest.java,其中第三个类是用来测试的。
Category.java代码:
       

package unsaved_value;    
import ......    
public class Category {    
    private Integer id;    
    private String name;    
    private String description;    
    private Set products;    
    public Category(){    
         id=null;    
         name=null;    
        description=null;    
        products=new HashSet ();    
     }    
     public void addProduct(Product p){    
         products.add(p);    
    }    
     //**********setter and getter    
    ........    
}   


Product.java代码:


package unsaved_value;      
public class Product {      
    private Integer id;      
    private String name;      
    private Category category;      
    private String description;      
    public Product(){     
         
    }      
     //*******getter and setter      
     .........      
}      

ConfigurationTest.java

public void testSave()throws Exception{    
        Category category=new Category();    
        category.setName("java编程书籍2");    
        category.setDescription("编程经典书籍2");    
        Product pro=new Product();    
        pro.setName("java编程思想2");    
        pro.setDescription("第四版中文版2");     
        pro.setCategory(category);    
        category.addProduct(pro);    
        Transaction tx=session.beginTransaction();    
        assert (session!=null):("session is null");    
        session.save(category);    
        tx.commit();    
    }    

     
Category代表产品目录,而Product代表产品,显然Category与Product是一对多的关系。Hibernate在映射一对多关系时,有两种方式,一种是单向一对多,一种是双向关系。两者相比,双向一对多的好处体现在两方面:首先,也是很明显的一点,由于是双向关联,我们在实际业务逻辑时将更方便,例如我们可以检索一个Category下的所有Product,同时还可以检索出Product属于哪个。其次,双向关系相对单向关系而言,在数据库的访问方面更有优势。这一点留在后面讲inverse时讲
。双向关联比单向关联唯一的”劣势“,就在于双向关联需要比单向关联多写一个映射文件,这不问题。使用双向关联实现这两个类同数据库的映射:

Category.hbm.xml:  
version="1.0" encoding="UTF-8"?>  

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >  
<hibernate-mapping package="unsaved_value">  
   <class name="Category" table="category">  
     <id name="id" column="id">  
       <generator class="native">generator>  
     id>  
     
     <property name="name" column="name"/>  
     <property name="description" column="description"/>


     <set name="products" table="product" lazy="true" inverse="true" cascade="all">  
         <key column="category"/>  
            <one-to-many class="Product"/>  
     set>  
     
   class>  
hibernate-mapping>  
  
Product.hbm.xml:


version="1.0" encoding="UTF-8"?>    
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >    
<hibernate-mapping package="unsaved_value">    
<class name="Product" table="product">    
     <id name="id" column="id" unsaved-value="null">    
         <generator class="native">generator>    
     id>    
         
     <property name="name" column="name"/>    
     <property name="description" column="description"/>    
       
     <many-to-one name="category"    
                  column="category"     
                  class="Category"    
     />    
   class>    
hibernate-mapping>    
        
现在把这个例子所牵涉到的知识一一展开:
一.inverse
    该词的译意是“反转”,反转什么——反转控制端,这项配置决定了由关联双方中的哪一方来维持关联关系(在数据库中表现为外键约束)。上述配置中,在Category.hbm.xml中将inverse设置为true,意思是说“我需要反转(控制端)”,反转的结果是由对方即Product来维持关联关系。用单向关联更容易说明”维持关联关系“是什么意思:考虑用单向关系来实现这个映射关系的情况,即由Category关联到Product,考虑下面的代码:

Product p=new Product();  
..setXXX  
Category c=new Category();  
..设置Category的属性  
c.addProduct(p);//建立起了c和p的关联关系  
session.save(c);  

会执行三条SQL语句:两条插入语句,分别插入c和p,然后还有一条update语句建立起c和p的关联(更新p的外键)。上面,我们说由Category端控制关联,因此p.setCategory(c)这样一句话是没用的,它并不会导致在插入p的时候就设置p的外键以建立起两者的关联关系,从而节省一条update语句。同时我们还会看到,如果在数据库模式中将p的外键设置成非空,这些代码将不能执行,因为在插入p时,由于c和p的关联关系还未建立起来,因此p的外键为空。回到双向关联上来,为了更清楚地明白inverse在双向关联中到底起什么作用,我们分别将其值设为true和false,看看打印出的的SQL有何区别:

inverse=true时的打印结果:

Hibernate: insert into category (name, description) values (?, ?)  
Hibernate: insert into product (name, description, category) values (?, ?, ?)   
inverse=false时的打印结果:

Hibernate: insert into category (name, description) values (?, ?)    
Hibernate: insert into product (name, description, category) values (?, ?, ?)    
Hibernate: update product set category=? where id=?   
       为什么inverse=true时会比inverse=false时少执行一条SQL语句?这是由控制端的不同造成的。前者说"我要反转控制,由Product来控制关联",因此在将p对象insert时,p已经设置了其category字段,从而建立了关联关系,而后者说"我不反转控制,由我自己来控制关联",因此在将p对象insert后,c为了维持两者的关联,还要去执行一次update,以更新p的外键,从而建立起两者的关联关系。
结论:对于一对多双向关系,始终在“一”那一方将其inverse设置成true,这样会提高性能。

二.cascade
   级联。当关联的"一"方进行某种动作(更新,删除)时,"多"方即使没有显式地进行编码,它也会自动进行同样的动作。cascade的可选值有:
all : 所有情况下均进行关联操作。即是save-update + delete
none:所有情况下均不进行关联操作。这是默认值。
save-update:在执行save/update/saveOrUpdate时进行关联操作。
delete:在执行delete时进行关联操作。
all-delete-orphan:A:级联save-update B级联delete C:删除所有孤儿项(orphan孤儿)。先看看父子关系,例如在Customer和Order的模型中,这两者便是父子关系,当一个Customer的生命周期决定Order的生命周期,如果一个Customer不在了,其相关的Order继续存在是毫无业务意义的。删除所有孤儿项的意思即是,删除所有与父对象失去关联关系的子对象。

三.lazy
    是否延迟加载。一般来说,应该延迟加载,即将lazy设为true。延迟加载的相关点很多,这在另外的学习笔记中总结。

四.unsaved-value
    以上是"一"方的重要配置,再看看"多"方的一个重要配置:unsaved-value,就像上面Product.hbm.xml中的设置那样,这一项在id的配置中设置。这一设置是与级联一起工作的。关于这一点,robbin讲的很清楚:
当你显式的使用session.save()或者session.update()操作一个对象的时候,实际上是用不到unsaved-value 的。某些情况下(父子表关联保存),当你在程序中并没有显式的使用save或者update一个持久对象,那么Hibernate需要判断被操作的对象究竟是一个已经持久化过的持久对象,是一个尚未被持久化过的内存临时对象。例如:
       Session session = ...;
Transaction tx = ...;  
Parent parent = (Parent) session.load(Parent.class, id);  
Child child = new Child();  
child.setParent(parent);  
child.setName("sun");  
parent.addChild(child);  
s.update(parent);  
s.flush();  
tx.commit();  
s.close();  
     在上例中,程序并没有显式的session.save(child); 那么Hibernate需要知道child究竟是一个临时对象,还是已经在数据库中有的持久对象。如果child是一个新创建的临时对象(本例中就是这种情况),那么Hibernate应该自动产生session.save(child)这样的操作,如果child是已经在数据库中有的持久对象,那么 Hibernate应该自动产生session.update(child)这样的操作。因此我们需要暗示一下Hibernate,究竟 child对象应该对它自动save还是update。在上例中,显然我们应该暗示Hibernate对child自动save,而不是自动 update。那么Hibernate如何判断究竟对child是save还是update呢?它会取一下child的主键属性 child.getId() ,这里假设id是 java.lang.Integer类型的。如果取到的Id值和hbm映射文件中指定的unsave-value相等,那么Hibernate认为 child是新的内存临时对象,发送save,如果不相等,那么Hibernate认为child是已经持久过的对象,发送update。unsaved-value="null" (默认情况,适用于大多数对象类型主键 Integer/Long/String/...)
当Hibernate取一下child的Id,取出来的是null(在上例中肯定取出来的是null),和unsaved-value设定值相等,发送save(child)
当Hibernate取一下child的id,取出来的不是null,那么和unsaved-value设定值不相等,发送update(child)
   unsaved-value的可选配置有:
none,any,null
unsaved-value="none"和unsaved-value="any"主要用在主键属性不是通过Hibernate生成,而是程序自己setId()的时候。unsaved-value="none"和unsaved-value="any"究竟有什么含义了。如果你非要用assigned不可,那么继续解释一下:
unsaved-value="none" 的时候,由于不论主键属性为任何值,都不可能为none,因此Hibernate总是对child对象发送update(child)
unsaved-value="any" 的时候,由于不论主键属性为任何值,都肯定为any,因此Hibernate总是对child对象发送save(child)
      大多数情况下,可以避免使用assigned,只有当你使用复合主键的时候不得不手工setId(),这时候需要你自己考虑究竟怎么设置unsaved-value了,根据你自己的需要来定。
      关于为什么不要使主键带有义务意义,robbin的解释很清楚:还是以上面的例子打比方,如果我们将Category的某一个性质(比如产品序号或者名称)作为主键,如果后来由于业务需要,我们把这个性质改了,那将不可僻免地要去修改与这个对象相关联的所有数据的外键,而如果我们只要代理主键,这个问题就可完全僻免。

posted @ 2009-03-30 16:06 张永耀 阅读(313) | 评论 (0)编辑 收藏

今天在写程序的时候发现了一个很奇怪的问题“ResultSet can not re-read row data for column”,用google一搜,原来是微软公司的驱动的兼容性不太好。有热心人总结了微软驱动的缺点:(1)如果采用jdbc-odbc驱动,那么就必须按照查询顺序来一次读取(不论有没有image或text,ntext类型)(2)如果采用微软提供的ms sql server jdbc driver,如果查询语句中,不存在image或text,ntext类型字段,那么可以按照无序获取(3)如果采用微软提供的ms sql server jdbc driver,如果查询语句中,存在image或text,ntext类型字段,那么就必须按照顺序读取,否则就会报告Driver]ResultSet can not re-read row data for column之类的错误(4)如果想不查询语句中有没有image或text,,ntext类型字段,都可以不按照顺序获取,或重复获取。那么就必须更换驱动,改用第三方的。 最后,我改用了第三方的驱动。测试成功。
posted @ 2009-03-27 14:25 张永耀 阅读(306) | 评论 (0)编辑 收藏

用delphi和VB实现浏览器中超长文件的上传
 

摘 要 本文通过delphi的Tihttp控件,将超大文件分割成几个小文件,通过构造的表单数据流,

            直接发送到接收数据网页,由vb编写的服务器端进行文件接收和还原

一、问题的提出:

本单位在开发课件生成系统时,需要通过浏览器向服务器指定目录传送大的音、视频文件。在微软asp中未提供相应的控件,asp.net虽然提供了form表单中的file控件进行文件上传,但对上传的文件有长度限制,文件长度大于50M上传会失败,而微软基于安全考量,file控件中的文件名在运行期间只读,这样利用微软提供的控件向服务器端上传长度超过50M的文件变为不可行,必须另劈蹊径。

二、解决方案

delphi以其强大的控件集,快速的RAD开发,深得程序开发人员的青睐,其最新控件集Indy,集成了大部分流行的Internet协议,包括TCPUDPDNSICMPFINGERFTPGOPHERHTTPPOP3SMTPTELNETWHOIS,而浏览器的传输协议为http。这样我们可以利用delphi7中的TIHTTP控件,将数据打包后上传到服务器端。基本思路为:开发两部分功能程序,一个为ActiveX控件,嵌入到网页中,负责将客户端本地上传文件分解成n个数据包,每个数据包直接编码成“multipart/form-data”格式的表单信息,依次调用TIhttp控件的post方法向服务器端发送信息。另一个为服务器端的com组件,接受发送过来的原始信息,将数据包拼接还原成文件保存到服务器的指定目录中。

三、技术要点:

    1Delyhi 7开发Active X控件要点:选择新建项目→Active x标签→Active Form→填入控件名可快速搭建一个Acfire X控件架构,产生一个表单和一个框架代码文件。

2.上传Active x控件设计要点:①表单控件中放置一个编辑控件、三个命令按钮、一个进度条控件、一个文本标签控件、一个文件对话框控件。编辑控件用来放置上传文件名。一个浏览按钮打开文件选择对话框,选择上传文件;进度条控件显示上传文件进度;文本标签显示上传文件百分比,取消按钮可中断文件上传。

②项目包含两个代码文件,其中一个文件用来将上传文件拆分成小数据包。其关键代码如下:

    for y:=0 to filenum  do

       begin

         if y=0  then   //第一个包

             begin

            if y <> filenum then

                  begin

                      for i:=1 to basenum do

                        begin

                           read(f,ch);

                           tempf:=chr(ch);

                           temp:=temp+tempf;

                          application.ProcessMessages;

                        end;

                    vflag:=postdata(vurl,vfilename,temp,'0');

                    end

                  else

                         begin

                         j:=0;

                            while not eof(f) do

                            begin

                              read(f,ch);

                            tempf:=chr(ch);

                            temp:=temp+tempf;

                            j:=j+1;

                            application.ProcessMessages;

                  vflag:=postdata(vurl,vfilename,temp,'-2');

                end;

               end

               else if y<> filenum then //中间包

                   begin

                      for i:=1 to basenum do

                        begin

                           read(f,ch);

                          tempf:=chr(ch);

                           temp:=temp+tempf;

                            application.ProcessMessages;

                        end;

                          vflag:=postdata(vurl,vfilename,temp,'1');

                  end

               else  //最后一个包

                 begin

                        j:=0;

                        while not eof(f) do

                       begin

                         read(f,ch);

                         tempf:=chr(ch);

                         temp:=temp+tempf;

                         j:=j+1;

                          application.ProcessMessages;

                     end;

                   vflag:=postdata(vurl,vfilename,temp,'-1');

                 end;

       end;

end;

③另一个文件用来将小数据包按照http格式封装成二进制文件上传数据流发送到指定的接收页面(URL),数据流除必要的头信息,包含两个表单城,一个数据块,其中一个表单域用来传递文件标记,用来区分本数据包是第一个包,中间包还是最后一个包,另一个表单域传递上传文件名,其关键代码如下:

   try

     filedata.Seek(0,sofrombeginning);

     tempstring:='';

     tempstring:=tempstring+'------------------------------7cf87224d2020a'+

         newline;

     tempstring:=tempstring+'Content-Disposition: form-data;name="vflag"'+newline;

     tempstring:=tempstring+''+newline;

     tempstring:=tempstring+vflag+newline;

     tempstring:=tempstring+''+newline;

     tempstring:=tempstring+''+newline;

     tempstring:=tempstring+'Content-Disposition: form-data; name="editfilename"; filename="'+infile+'"'+newline;

     tempstring:=tempstring+'Content-Type: application/octet-stream'+newline;

     tempstring:=tempstring+''+newline;

     fillchar(temparray,sizeof(temparray),#0);

     strpcopy(temparray,tempstring);

     request.Write(temparray,length(tempstring));

     request.seek(0,sofromend);

     request.CopyFrom(filedata,filedata.size);

     tempstring:='';

     tempstring:=tempstring+''+newline;

     tempstring:=tempstring+'------------------------------7cf87224d2020a--'

          +newline;

     fillchar(temparray,sizeof(temparray),#0);

     strpcopy(temparray,tempstring);

     request.write(temparray,length(tempstring));

     try

       http.Post(url,request,response);

       if pos('成功',response.datastring)<>0 then

          flag:=1

     end.

End.

④本ActiveX控件特色:可以实时显示上传进度,并能随时中断文件的上传,上传页面画面如图所示,可不能随时中断文件上传,即应用程序能随时从循环语句中跳出,在循环语句中使用了ayydicdition Process Messages语句,该语句用来监听和处理系统消息这样就有效避免了文件上传时,不能进行系统的其它操作。

3.用VB6.0开发服务器端接收文件的Activeex dll,主要利用VB6.0强大的网页操作功能,引用库文件microsoft Active sever Page object library。其中包含有asp对象Asp library request。创建一个接收函数load,使用request对象读取上传给接收页面的二进制数据流,分离出上传标志、上传文件名以及文件内容,根据上传标志将分段传送来的文件内容拼接成一个完整的文件,保存到指定目录。

四、几点说明

    1.本程序在操作系统为Win98 Win2000的客户端机器,IIS服务器端为Win 2000的环境下调试通过;

2.将upfile.htmupload.aspmyget.dllupfileproj1.ocx文件放置到IIS服务之虚拟目录upfile下(缺省目录为C:"Inetpub"unnroot"upfile);

3.修改upfile.htmcodebase属性(缺省为http://11.68.17.80/upfile/upfileproj1.ocx)中的IP地址为服务器端地址;

4.修改delphi工程文件upfileprojl中的upfilelmpl1文件中的Button2 click事件中的vulstring=’http://11.68.17.80/upfile/upload.asp’一行数据,将其中的IP地址转接为服务器端地址,重新编译后将upfrleprojl.ocx放置到虚拟目录下;

5.上传文件在服务器端的默认保存目录为c:"temp;

6.须手工注册myget.dll,命令语句为regsvr32  C:"inetpub"wwwroot"upfile"myget.dll

7.览器中敲击网站地址执行,缺省地址为http://11.68.17.80/upfile/upfile.htm
posted @ 2009-03-27 08:48 张永耀 阅读(486) | 评论 (0)编辑 收藏

我们的产品中间件的启动是由批处理文件开始,这就导致,始终有个DOS窗口,来显示服务器的运行情况。可客户不乐意啊:他们就想万一谁不小心把那窗口给关了,损害了数据,那问题可就大了!这个问题确实是挺有价值的。
首先,我们考虑WINDOWS环境吧,我不认为WINDOWS环境下和*NIX环境下的实现有很大差别。想到以前看到的,听到的,再加上自己的经验,大概有这么集中方式:
  • 包装bat文件为exe文件,然后以后台服务的形式注册
  • 利用windows自带的Wscript.Shell
  • 写个Swing界面小程序,利用多线程,启动应用服务,把DOS窗口替换成应用窗口。
  • 但我们需要考虑另外一点:我们的应用在运行的时候,会向dos窗口输出一些出来的一些信息,这些信息在很多情况下都是很有用的。现在如果把DOS窗口隐藏了,那么那些信息我把他们存放到哪儿呢?我想最好还是以文件的形式保存起来,将来如有问题还可以追查!
    现在考虑各种实现方式。包装为exe的形式,也只能在windows环境下运行,并且需要额外的工具;Swing界面小程序这个其实是最可行的,但我这个人比较懒,比较讨厌写界面;利用windows自带的Wscript.Shell,自然也只能依赖于windows环境,后来我想了下,其实这个方案可以和swing界面那个方案有不少东西是可以公用的。最后决定,为了简单期间,偶就先用Wscript.Shell,来做测试了。
    实际的情况大致是:
  • 应用服务的启动脚本是/startup.bat 实际中我们可以使用vbs脚本:
  • dim ws
    Set ws = CreateObject("Wscript.Shell")
    ws.run "cmd /c /startup.bat >> myServer.log" ,vbhide
    通过这样简单的设置,我们可以做到隐藏DOS窗口,但是,如果我们的应用一下子运行好几个月,那我们的日志文件myServer.log的日积月累地,就太大了。我们在查找问题的时候,也很不容易!所以我们应该想法子把日志文件myServer.log,按时间或者按大小分开存储。这也是我们应用服务器日志的做法。所以,我们需要再做一步中间处理,想想看"appRoot/startup.bat"这一步,我们在程序当中还是可以获得它的输出结果的。看下面java程序:
    package nc.client.StartupUtil;

    import java.lang.ProcessBuilder;
    import java.util.Vector ;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.FileWriter;
    import java.io.BufferedWriter;
    import java.util.Collections ;

    public class NC50StartUtil
    {

    public static final String logFileNamePrefix = "ncconsolelogs";

    public static void main(String[] args)
    {
    ProcessBuilder processBuilder = new ProcessBuilder("cmd", "/C", args[0]+"/startup.bat");
    processBuilder.directory(new File(args[0]));
    Process process = null;
    try
    {
    process = processBuilder.start();
    BufferedReader datais =
    new BufferedReader(
    new InputStreamReader( process.getInputStream()));


    // 服务器日志目录
    String serverLogDirName = args[0] + "/nclogs/server";
    File serverLogDir = new File (serverLogDirName);
    if (!serverLogDir.exists())
    {
    serverLogDir.mkdirs();
    }

    int maxFileIndex = getMaxFileIndex(serverLogDirName).intValue();
    File logFile = new File(serverLogDirName+"/ncconsolelogs.log");
    if (!logFile.exists())
    {
    logFile.createNewFile();
    }
    else
    {
    // 如果已经存在日志文件,则先把原来的文件归档,然后新创建一个日志文件
    StringBuffer oldFileName = new StringBuffer();
    oldFileName.append(serverLogDirName);
    oldFileName.append("/");
    oldFileName.append(logFileNamePrefix).append("[").append(maxFileIndex).append("].log");
    logFile.renameTo(new File(oldFileName.toString()));
    maxFileIndex++;
    //创建新的日志文件
    if (!logFile.exists())
    {
    logFile.createNewFile();
    }

    }

    BufferedWriter writer = new BufferedWriter(new FileWriter(logFile));

    // 文件的最大大小是2M
    int maxlength = 1024*1024*2;

    String c;
    while ((c = datais.readLine()) != null)
    {

    writer.write(c);
    writer.newLine();
    writer.flush();

    // 超过日志文件规定的大小了,则把日志文件归档,然后新创建一个日志文件
    if (logFile.length() > maxlength)
    {
    writer.close();
    StringBuffer oldFileName = new StringBuffer();
    oldFileName.append(serverLogDirName);
    oldFileName.append("/");
    oldFileName.append(logFileNamePrefix).append("[").append(maxFileIndex).append("].log");
    logFile.renameTo(new File(oldFileName.toString()));
    maxFileIndex++;

    // 创建新的日志文件
    if (!logFile.exists())
    {
    logFile.createNewFile();
    }
    writer =   new BufferedWriter(new FileWriter(logFile));
    }

    }
    }
    catch(IOException e)
    {
    e.printStackTrace ();
    }
    }

    public static Integer getMaxFileIndex(String ncconsolelogdirname)
    {
    File ncconsolelogdir = new File(ncconsolelogdirname);
    File[] ncconsolelogs = ncconsolelogdir.listFiles(new NcLogFileNameFilter(logFileNamePrefix));

    if (ncconsolelogs != null && ncconsolelogs.length > 0)
    {
    Vector v = new Vector();
    for (int i=0, len=ncconsolelogs.length; i startIndex)
    {
    String index = logFileName.substring (startIndex+1, endIndex);
    int ind = -1;
    try
    {
    ind = Integer.parseInt(index);
    }
    catch(Exception e)
    {

    }

    if (ind > 0)
    {
    v.add(ind);
    }
    }
    }
    if (v.size() > 0)
    {
    return Collections.max(v) + 1;
    }
    else
    {
    return 1;
    }
    }

    return 1;
    }
    }
    package nc.client.StartupUtil;

    import java.io.File;
    import java.io.FilenameFilter;

    // 一个简单的文件名过滤类
    public class NcLogFileNameFilter implements FilenameFilter {

    private String fileNamePrefix = null;

    public NcLogFileNameFilter(String fileNamePrefix)
    {
    this.fileNamePrefix = fileNamePrefix;
    }

    public boolean accept(File dir, String name)
    {
    if (name.toLowerCase().startsWith(fileNamePrefix))
    {
    return true;
    }
    return false;
    }
    }
    之后,为了运行方便,我们把这两个类编译后打成可执行的jar包,例如ncstartuputil.jar。并修改vbs脚本为:
    dim ws
    Set ws = CreateObject("Wscript.Shell")
    ws.run "cmd /c java -jar ncstartuputil.jar E:/nchome_zhengshi" ,vbhide
    如果换做swing界面,其实仅仅需要写另外一个Thread,thread的主体也正式上面static main方法主体,然后通过多线程,可以获得原始start.bat批处理文件的输出,并且把输出的信息放到一个textarea里面显示出来。:-)....
    posted @ 2009-03-26 17:16 张永耀 阅读(737) | 评论 (0)编辑 收藏

    最近做在做一个项目,涉及到文件上传的问题。 以前也做过文件上传。但都是些小文件,不超过2M。 这次要求上传1G以上的东西。 没办法找来资料研究了一下。 基于WEB的文件上传可以使用FTP和HTTP两种协议,用FTP的话虽然传输稳定,但安全性是个严重的问题,所以没有考虑。 剩下只有HTTP。 在HTTP中有3种方式,PUT、WEBDAV、RFC1867,前2种方法不适合大文件上传,在这里也不说了。
    确定使用RFC1867格式处理之后开始分析流行的上传组件。看了N多代码之后发现,目前无组件程序和一些COM组件都是使用Request.BinaryRead方法。一次性得到上传的数据,然后分析处理。这就是为什么上传大文件很慢的原因了,IIS超时不说,就算1G文件上去了,分析处理也得一阵子。 之后我把注意力放在国外商业组件上,比较流行的有Power-Web,AspUpload,ActiveFile,ABCUpload,aspSmartUpload,SA-FileUp。其中比较优秀的是ASPUPLOAD和SA-FILE,他们号称可以处理2G的文件(SA-FILE EE版甚至没有文件大小的限制),而且效率也是非常棒,难道编程语言的效率差这么多?(我的编程环境是VB6) 查了一些资料,觉得他们都是直接操作文件流。这样就不受文件大小的制约。 真是个好方法。
    但老外的东西也不是绝对完美,ASPUPLOAD处理大文件后,内存占用情况惊人。1G左右都是稀松平常。我用的是3.0.0.3版。至于SA-FILE虽然是好东西但是破解难寻(郁闷死..) 失望之际,发现2款上传组件,Lion.Web.UpLoadModule和AspnetUpload,都是.NET的,估计也是操作文件流。但是上传速度和CPU占用率都不如老外的商业组件。
    做了个测试,LAN内传1G的文件。ASPUPLOAD上传速度平均是4.4M/s,CPU占用10-15,内存占用700M。SA-FILE也差不多这样。而AspnetUpload最快也只有1.5M/s,平均是700K/s,CPU占用15-39,测试环境:PIII800,256M内存,100M LAN。我想AspnetUpload速度慢是可能因为一边接收文件,一边写硬盘。资源占用低的代价就是降低传输速度。 但也不得不佩服老外的程序,CPU占用如此之低.....这样2个.net的组件也被PASS.

    稍带2个问题就是上传进度和断点续传。
    显示上传进度比较简单,主要是查询用户上传的状态,用Script显示到浏览器中,至于无刷新显示就要看脚本语言运用的熟练程度了。
    断点续传,HTTP方式是实现不了的,因为浏览器每次上传文件都是从头开始,没有Range标签。实现的方法只能用ActiveX。

    研究之后决定写个CGI来处理文件上传。 这样可以不走IIS以免程序出错影响网站访问。小弟比较菜只能用VB6做,完成之后发现WIN CGI的效率简直就是差的不能再差。索性写个FILE SERVER,专门处理文件的上传。但是现在遇到一个2个问题。
    一、用WINSOCK控件接收到的文本有乱码 不知道是程序转换时的错误还是WINSOCK本身垃圾,SO 换了PowerTCP的WINSOCK TOOL,情况有所好转 乱码没那么多了.........准备换vb.net,直接操作socket,程序还没做,不知道用.net接收会不会乱码。再有就哭了。
    二、这个问题就比较初级了....接收到的文件流不能还原成文件..寒一个,

    最后就是如何高效处理文件流, 我想来想去也就只有2种方法,一是都放在内存里,然后一起处理, 二是一边接收一边写文件。 但这2种方法都不尽如人意思
    posted @ 2009-03-26 17:00 张永耀 阅读(123) | 评论 (0)编辑 收藏


    http://cydn.8k.com      http://cydn.8m.com     http://cydn.s5.com

    登陆修改地址:http://cydn.8k.com/cgi-bin/login

    http://cydn.8k.com/cgi-bin/login

    http://cydn.s5.com/cgi-bin/login


    1。  个人空间和Blog   http://zhoubing518.x.27h.org/

    也就是: http://www.27h.com/blog/html/03/143103.html

    支持Ftp上传,地址:ftp.27h.com  最好用CutFtp工具上传。用户名密码为登陆的用户名和密码

    支持Html解析,不能解析jsp,属于WEB服务器。

    网站的信件内容如下:

         尊敬的 cydn 用户你好!
        我是酱子家园的管理员!
    感谢您申请我们的免费主页服务,您已经成为我们的用户。
    ======================================================================
    您的FTP地址为 ftp://ftp.27h.com
    用户名为 cydn
    目前空间大小为 50M 您的主页地址为 http://cydn.27h.com

    您必须安装FTP软件,例如LEAPFTP CUTEFTP等

    2.    速度最快,最稳定的一个:  http://hi.baidu.com/zbzb  

    不能上传自己的Html页面.但有100M的照片库  

    3.   个人空间   http://zb.s5.com    国外免费空间,支持Html .用户登陆页:http://www.s5.comhttp://www.s5.comhttp://www.s5.comhttp://www.s5.com    国外免费空间,支持Html .用户登陆页:http://www.s5.com

    登陆修改地址:http://zb.s5.com/cgi-bin/login

    4.   个人Blog  博客地址:http://zb66.139.com   您的用户名:zb66  您的密码:***
    手机登陆的WAP地址:http://zb66.m.139.com     页面不是很好看,模版少。速度快,.net网站。

    5.  http://host.tomore.com   

    主机名:http://host.tomore.com/cydn/

    FTP:

    主机:host.tomore.com
    用户名:cydn
    密码:你的会员密码.
    空间大小:50 M .

    Mysql:未开通,请升级为正式会员!

    5.  我申请的几个免费域名

    我申请的域名:
    http://cydn.wyou.cn
    http://smys.9126.com
    http://smys.9126.com
    http://cydn.1www.cn/http://xacydn.9126.com
    圣博个人免费空间:
    http://cydn.home.sunbo.net

    6.  免费域名申请网址简介:

    http://www.wyou.cn/reg/reg.asp   
    免费域名服务由万游网提供

    http://www.xinfree.com/default.htm

    申请地址:http://www.008.net/free/

    申请网址:http://ew88.com/reg.asp

    申请地址:http://www.eee.cc/

    申请网址: http://www.chinese.cn.com/freedomain/
    CHINESE.cn.com 免费域名开始测试,域名长度要求在3至20个字符之间。 您可以注册以下域名:
    yourname.chinese.cn.com
    yourname.163.cn.com
    yourname.263.cn.com
    yourname.sina.cn.com
    yourname.sohu.cn.com
    yourname.tom.cn.com
    快来抢注呀!

    申请网址: http://reg.900du.com/

    免费 ***.k6.cn域名!
    申请网址: http://jsyzt.k6.cn/reg/reg.asp

    申请网址:http://mycool.net/

    申请网址:http://my.k6.cn/reg/reg2.asp

    很不错的免费域名,共27种后缀,例如:cc.ly/tv.ly/cn.ly/on.ly,快去申请吧!

    申请网址:
    http://tv.ly/

    可选择的后缀有:   hk.ly   dj.md   ok.mu   n.md   w.md   hk.md   tea.ms   email.ly   cn.ly   jp.ly   kr.pn   cc.ly   tv.ly   co.kr.mw   co.kr.pn   name.md   kr.mw   to.tc   email.dj   blog.vg   on.ly   cc.la   cn.la   tw.la   jp4.jp   na.la   wa.la

    Lycos中国免费聊天室申请! 
    时间: 2004-07-12 21:08:37 | [<<] [>>]
    --------------------------------------------------------------------------------
        免费提供个人聊天室,申请简单,只需在主页添加一段html代码即可,没有广告,速度尚可,但功能较少。

    申请网址: http://chat.lycos.com.cn/hkcn/code.html
    碧聊免费聊天室申请!
    --------------------------------------------------------------------------------
    免费提供支持10人的语音聊天室,速度快、功能强,如果需要更大在线人数可以购买收费服务。

    申请网址: http://www.bliao.com/help/help23.htm

    posted @ 2009-03-26 14:12 张永耀 阅读(111) | 评论 (0)编辑 收藏

    阅读全文
    类别:数据库 查看评论
    文章来源:http://hi.baidu.com/zbzb/blog/item/286f8b5438a4bf183b293556.html
    posted @ 2009-03-26 13:21 张永耀 阅读(48) | 评论 (0)编辑 收藏

    阅读全文
    类别:免费资源 查看评论
    文章来源:http://hi.baidu.com/zbzb/blog/item/ef6dae7724dae11cb151b9d4.html
    posted @ 2009-03-26 13:21 张永耀 阅读(61) | 评论 (0)编辑 收藏

    阅读全文
    类别:底层软件 查看评论
    文章来源:http://hi.baidu.com/zbzb/blog/item/9013d0ca2ad45241f31fe763.html
    posted @ 2009-03-26 13:21 张永耀 阅读(83) | 评论 (0)编辑 收藏

    仅列出标题
    共3页: 上一页 1 2 3 下一页