??xml version="1.0" encoding="utf-8" standalone="yes"?> /* import java.io.BufferedReader; public final class AccessTextFile { /** /** /** /** public static void main(String[] args) throws IOException { } Java ?写文件文本文件的CZ
* 单的?写文本文件的CZ
* q里包含了三个例子,?br /> * 1. 文件读入到内存Q这里是StringBufferQ的例子
* 2. 内容中的文本写到文?br /> * 3. 一个文件的内容d来写入另一个文件中
* 同时也展CZ如果从输入流中读出来内容写入输出中Q仅限文本流Q?br /> * 三个例子可以独立存在Q所以根据需要只看其中一个就行了?br /> */
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.PrintWriter;
* 1. 演示流中的文本d一?StringBuffer ?br /> * @throws IOException
*/
public void readToBuffer(StringBuffer buffer, InputStream is)
throws IOException {
String line; // 用来保存每行d的内?br /> BufferedReader reader = new BufferedReader(new InputStreamReader(is));
line = reader.readLine(); // dW一?br /> while (line != null) { // 如果 line 为空说明d?br /> buffer.append(line); // 读到的内容d?buffer ?br /> buffer.append("\n"); // d换行W?br /> line = reader.readLine(); // d下一?br /> }
}
* 2. 演示?StringBuffer 中的内容d到流?br /> */
public void writeFromBuffer(StringBuffer buffer, OutputStream os) {
// ?PrintStream 可以方便的把内容输出到输出流?br /> // 其对象的用法?System.out 一?br /> // QSystem.out 本n是 PrintStream 对象Q?br /> PrintStream ps = new PrintStream(os);
ps.print(buffer.toString());
}
* 3*. 从输入流中拷贝内容到输入中
* @throws IOException
*/
public void copyStream(InputStream is, OutputStream os) throws IOException {
// q个读过q程可以参阅 readToBuffer 中的注释
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
PrintWriter writer = new PrintWriter(new OutputStreamWriter(os));
line = reader.readLine();
while (line != null) {
writer.println(line);
line = reader.readLine();
}
writer.flush(); // 最后确定要把输出流中的东西都写出去?br /> // q里不关?writer 是因?os 是从外面传进来的
// 既然不是从这里打开的,也就不从q里关闭
// 如果关闭?writerQ封装在里面?os 也就被关?br /> }
* 3. 调用 copyStream(InputStream, OutputStream) Ҏ拯文本文g
*/
public void copyTextFile(String inFilename, String outFilename)
throws IOException {
// 先根据输?输出文g生成相应的输?输出?br /> InputStream is = new FileInputStream(inFilename);
OutputStream os = new FileOutputStream(outFilename);
copyStream(is, os); // ?copyStream 拯内容
is.close(); // is 是在q里打开的,所以需要关?br /> os.close(); // os 是在q里打开的,所以需要关?br /> }
int sw = 1; // 三种试的选择开?br /> AccessTextFile test = new AccessTextFile();
switch (sw) {
case 1: // 试?br /> {
InputStream is = new FileInputStream("E:\\test.txt");
StringBuffer buffer = new StringBuffer();
test.readToBuffer(buffer, is);
System.out.println(buffer); // 读?buffer 中的内容写出?br /> is.close();
break;
}
case 2: // 试?br /> {
StringBuffer buffer = new StringBuffer("Only a test\n");
test.writeFromBuffer(buffer, System.out);
break;
}
case 3: // 试拯
{
test.copyTextFile("E:\\test.txt", "E:\\r.txt");
}
break;
}
}
]]>
XF86Config-4文g是Xpȝ的主要配|文件。在Redhat 8以前版本中都叫做XF86Config-4q个名字QRedhat 8已经不再叫做q个名字?
~辑q个文g需要小心}慎一点,因ؓ一炚w误,你的X不能启动。不果没关系啦,改回来就是了学习Linux最好的办法当然q是求助于男人(manQ,大家有什么问题尽看看man的帮助就是了。如果你要删除文件中的内容,最好不要直接的删除Q而应该在前面加上#W号把它变成注释?
在Redhat 8以前的版本中QX的配|工hXconfiguratorQ在Debian中X的配U方法是Q?
dpkg-reconfigure xserver-xfree86
当然你都得用root的n份来q行?
?usr/share/doc/xfree86-common/FAQ.gz文g中你可以看到具体的技巧?
W一D|FilesD,q个部分用来配置Xpȝ说能够用的字体Q每一行都代表一个目录,保存了具体的字体和字体的配置信息?
代码:
Section "Files"
FontPath "/usr/X11R6/lib/X11/fonts/xp"
FontPath "/usr/X11R6/lib/X11/fonts/XChinese"
FontPath "unix/:7100" # q是本地字体服务?
# 如果本地字体服务器出了问题,我们可以使用下面的配|?
FontPath "/usr/lib/X11/fonts/misc"
FontPath "/usr/lib/X11/fonts/cyrillic"
FontPath "/usr/lib/X11/fonts/100dpi/:unscaled"
FontPath "/usr/lib/X11/fonts/75dpi/:unscaled"
FontPath "/usr/lib/X11/fonts/Type1"
FontPath "/usr/lib/X11/fonts/Speedo"
FontPath "/usr/lib/X11/fonts/100dpi" #q两个字体是每一个X
FontPath "/usr/lib/X11/fonts/75dpi" #pȝ都必需安装的英文字?
EndSection
下面的是模块D,用来配置Xpȝ加蝲的模块?
代码:
Section "Module"
Load "xtt" #gtk1使用的字体引擎,效果好,速度E慢
Load "GLcore" #如果你是用的是Nvidia的显卡,g一定要注消掉这一?
Load "bitmap"
Load "dbe"
Load "ddc"
Load "dri"
Load "extmod"
# Load "freetype" #如果你用了xtt模块Q那么freetype模块需要注消掉
Load "glx"
Load "int10"
Load "record"
Load "speedo"
Load "type1"
Load "vbe"
EndSection
下面的段是用来配|你的键盘的Q属于“输入设备?
代码:
Section "InputDevice"
Identifier "Generic Keyboard" #q是你的键盘的名字,随便你啦
Driver "keyboard" #键盘的驱动…哇Q键盘也有驱?
Option "CoreKeyboard" #如果你有多个键盘Q那么你需要在q里指定哪一个键盘是主要的键?
Option "XkbRules" "xfree86"
Option "XkbModel" "pc104" #键盘的分布格式,一般来?
Option "XkbLayout" "us" #国104键盘是大安用的?
EndSection
q里配置你的鼠标Q当然你可以配置两个鼠标Q如果你有的?
代码:
Section "InputDevice"
Identifier "Configured Mouse" #鼠标的名?
Driver "mouse" #鼠标的驱?
Option "CorePointer"
Option "Device" "/dev/input/mice"
#注意Q这里很重要Q这是鼠标的讑֤文g
#我的鼠标是光电鼠标,用的USB接口Q对应的鼠标文g?dev/input/mice
#如果你的鼠标是普通的滚轮鼠标Q用的是PS2接口Q那么你应该使用
#/dev/mouse或?dev/psaux或?dev/ttys0q个讑֤
Option "rotocol" "ImPS/2"
#q是鼠标的类型,如果不是是滚轮鼠标,那么使用PS/2
Option "Emulate3Buttons" "true"
#在Linuxpȝ中,鼠标的第三个键非常有用,
#如果你的鼠标没有W三个键Q那么我们应该允怋用双键同时点L模拟
Option "ZAxisMapping" "4 5"
EndSection
下面的设备是昑֍Q这是最头痛的设备了Q如果你的显卡太新潮Q很有可能不能支持哦。Nvidia的GForce2昑֍必需自己~译昑֍的驱动程序才能?
代码:
Section "Device"
Identifier "Generic Video Card"
Driver "ati" #如果你是Nivida的显卡,q里应该?nvidia"
EndSection
q个讑֤是显C器?
代码:
Section "Monitor"
Identifier "Generic Monitor" #昄器的名字
HorizSync 30-60 #昄器的频率Q一半来说你的显C器
VertRefresh 50-75 #应该可以辑ֈ我的q个水^
#因ؓ我的昄器是15"的老显C器?
#大家的电脑都比我的好吧?
Option "DPMS"
EndSection
下面是综合以上你的配|的讑֤的各U显C效?
代码:
Section "Screen"
Identifier "Default Screen" #效果的名?
Device "Generic Video Card" #你可以指定你的显卡的名字
Monitor "Generic Monitor" #指定你的昄器的名字
DefaultDepth 24 #默认的颜色深?
SubSection "Display"
Depth 1
Modes "1024x768"
EndSubSection
SubSection "Display"
Depth 4
Modes "1024x768"
EndSubSection
SubSection "Display"
Depth 8
Modes "1024x768"
EndSubSection
SubSection "Display"
Depth 16
Modes "1024x768" #在这里你可以指定扫描频率例如
#"1024x768 @ 85"是?5mhz的频?
EndSubSection
SubSection "Display"
Depth 24
Modes "1024x768"
EndSubSection
EndSection
最l你必需定义下面的段用来告诉X服务器你使用的配|?
代码:
Section "ServerLayout"
Identifier "Default Layout" #刚才我们l我们的配置取的名字
Screen "Default Screen" #l我们的效果取的名字
InputDevice "Generic Keyboard" #我们的键盘的名字
InputDevice "Configured Mouse" #我们的鼠标的名字
#q些名字一定要在前面的配置中已l定?
EndSection
Section "DRI"
Mode 0666
EndSection
一般来说我们X启动时候会遇到的问题是Q?
1Qno screen found
q有可能是你没有正确的定义所需要的效果Q也有可能是你的其他部分定义出错倒置你的效果不能实现
2Qxtt和freetype的冲H,注消一个就可以?
3Q驱动没有找刎ͼ如果你的昑֍非常的新潮,那么多半是这个错误了Q编译你的驱动吧?/font>
]]>
你一定非常希望立ȝ到那些非常漂亮的囑Ş界面Q但是也许我要让你失望了。我在没有用图形界面以前,首先熟练的掌握基本的Linux命oQ这h是一个真正的Linuxer。从哪里开始呢Q?
1. ls 列出文g和目录的命o
你一定很想知道你的电脑里面有哪些东西Q现在执行命令lsQ啊Q怎么什么都没有Q当然啦Q这是你W一ơ登录到q个pȝQ你的默认位|是你的个h目录Q而不是系l根目录。你q没有在q个目录里面存放M的个人文Ӟ当然什么都没有啦。如果你是用root用户d的话Q你的个人目录就?root目录Q如果你是用普通用L录,比如叫做krisQ那么kris的个人目录是/kris。前面的/是什么意思呢Q就是“根”的意思,是最前面的那个目录,在根目录下面建立有很多的子目录,我们在第一章已l讨了?
ls命o有很多的选项Q常用的是:
-A 选项用来列出所有的文gQ包括那些隐藏的文g。ؓ什么我们要隐藏文g呢?道理和你Z么要把情书藏h不让爸妈发现是一L。就是ؓ了保密啊。现在执行ls -A看看Q是不是有一个隐藏文件?bashrc”被昄出来啦?聪明的你一定奇怪的发现q个文g名前面有一个点Q对Q记住,只要文g名前面第一个字W是一个?”,q个文g是隐藏文g。一个目录名前面的第一个字W如果是?”这个目录就是隐藏目录?
-l q个选项用来昄一个列表,包含了这个目录下面所有的文g的绝大部分属性的列表。你可以每个文g的大,所有者,你的权限q有修改日期{等?
-R R的意思就是recursive递归Q明显这个选项让系l显C出q个目录下面的所有文件以外,q要昄出所有子目录下面的文件。也是把我们那一大堆水果全部抖出来?
--color q个选项特别有用Q我估计大家的显C器都是彩显吧,什么?你的昄器还是黑白的Q天哪!既然是彩显,那么我们可以让ls命o用不同的D代表不同的文件类型。比如可执行文g用绿Ԍ普通文件是白色Q目录是蓝色。也怽会问Q目录也是文件吗Q对的,在Linux里面一切都是文Ӟ所有的g讑֤都用一个文件来代替Q比如你的Y驱,是?dev/fd0来代替的。目录也是一个文件?
--help q个选项几乎是每一个Linux命o都有的,用来昄命o的帮助信息?
2. cd ?mkdir 以及 rm 改变当然所在目录,建立新目录以及删除目录命?
热打铁的,刚才说了目录Q我们每一ơ登录都有一个默认目录就是我们的个h用户目录。我们怎么才能到其他的目录dQcd是用来改变当前所在的目录的。前面我们说q,?”代表根目录Q那么执行cd /可以进入根目录。不试一下吗Q?
让我们看看根目录下面有哪些文件和子目录吧Q执行lsQ我们发玎ͼ根目录下面有一个目录名子特别变态,叫做usrQ进ȝ看,cd usrQ看看这里面有什么?你会发现一个更psychoQ变态)的目录叫做srcQ进入src目录看看Q没什么好玩的。那么我们现在回到刚才的usr目录Q怎么做?是不是cd usrQ执行试一下,好像不行Q系l报告出?cd: usr: No such file or directory。这是怎么搞的Q问题在于我们现在所在的目录?usr/src下,我们执行cd usr的意思是q入/usr/src/usr目录而不?usr目录。正的Ҏ是cd /usr?
好比你在中华美食的筐里面看到一个四川的筐Q里面有一个成都的箩{,现在你进入以后发现成都的箩{里面有一U叫做“麻辣烫”的很G的食品。你大饱口福以后惌吃一些甜点,于是准备ȝ州。你能站在成都的筐里面ȝ州吗Q当然不行,州q不在成都的筐里面啊,你应该进入?中华食/州”而不是?中华食/四川/成都/州”对不对Q?
好的Q一个问题出CQ难道我每一ơ进入一个目录,都要?usr/src...q么复杂的方式来表示吗?不一定。我们用?.”的方式来表CZ一层目录。如果你现在?usr/src目录下,q入/usr目录有两U办法:cd /usr和cd ..他们是一L?
怎样才能知道我现在在哪个目录Q用命opwdQ这个命令没有什么好说的Q执行一ơ就知道了?
现在我想在我自己的个人目录里面徏立一个目录叫做LoveLetter。我应该首先回到我自q目录Q这里有一个简单的ҎQ就是直接运行cd不带M参数Q这样就可以回到自己的目录,当然也可以cd /root或者cd /home/krisQ看你是用什么用L录的?
q入我自q目录以后Q徏立新目录的命令是
mkdir 新目录名
我执?mkdir LoveLetter 可以徏立一个新的叫做LoveLetter的目录。进入这个目录看看?什么都没有。不着急,慢慢来。我都不着急你急什么?
H然我想赯台电脑我的爸妈也要用,他们看到我的情书目录怎么办?你忘了刚才我说的可以用加一个点?”在前面的方法来隐藏目录和文件的Q我们可以改变这个目录的名字Q但是这个命令我准备{会儿讲Q现在我们用一个很无聊的办法来完成q个要求。这个办法就是删掉刚才徏立的oveLetter目录在新Z?LoveLetter目录Q之所以说q个办法很无聊,是因为我们现在是在做实验Q如果来真的Q你原意删掉你的情书吗?是不是另有新Ƣ啦Q哈哈?
删除目录的命令其实也可以删除文gQ就是rm?
rm 待删除的文g?目录?
我记得Redhat会提CZ是不是真的要删除。按y是定Q按n是取消。如果Redhat没有提示你,那么{会h据我说的Ҏ修改一下系l让它提C咱们。免得以后心痛。删除一个文件很单。麻烦的是删除一个目录,如果一个目录里面已l有文gQrm是不让直接删除的Q你必需先把目录里面的所有文件删除,再删除目录。但是有一个参数可以改变一下,是 -rf Q这个参数有一定的危险性,因ؓ即ɾpȝ本来要提醒一下是不是真的删除目录Q加上这个参C不会有提CZ。执行rm 目录 -rf会在一眨眼的时间里面让你的资料下课Q?
那么我现在就删除LoveLetter目录了:rm LoveLetter -rf
建立一个新的目录mkdir .LoveLetter
现在ls看看Q是不是看不到LoveLetter目录了?但是ls -Aq是能看到的。所以这U隐藏方式只能偏偏自己,真正让你的文件安全的方式q是以后再讲吧?
3. mv 改变文g名和目录名的命o
cp 复制文g和目录命?
man 命o使用Ҏ参考工?
mv 老文件名 新文件名
mv 老目录名 新目录名
可以改变文件或者目录的名字?
我现在想要把刚才的这个目?LoveLetter改名回去Q因U无聊的隐藏方式很变态,我们有更高的方法来做这样一件事情:是不要告诉爸妈你的密码Q!Q?
mv .LoveLetter LoveLetter
cp命o用来把一个文件复制成Z个新的文Ӟ
cp 老文件名 新文件名
q个老文件明和新文g名如果在同一个目录下面,那么当然需要名字不一P很简单的道理Q如果文件名一样何必徏立两个文Ӟ如果新老文件在不同的目录,我们可以让它们有相同的名子。下面的例子说明了这一点:
cp LoveLetter LoveLetter_yesterday 新的文gLoveLetter_yesterday和旧的LoveLetter在同一个目录,所以名子不一栗?
cp LoveLetter /home/LoveLetter 新的文g?home目录下面Q但是旧的文件LoveLetter在某一个用L个h目录下面Q当然两者名子可以相同?
cp命o也可以复制整个目录,但是现在我们暂时不讲q么复杂。其实cpq有rm以及lsq些命o不仅是整个Linux的基本命令,更包含了非常多的功能。如果大家有兴趣Q可以用man
man 命o名字
比如man lsQ这样就可以看到所有ls命o和参数的详悉解释Q尤其是一部分常用的命令的man帮助已经由志愿者翻译了Q大家看h更容易?
一点幽?
好了Q说了好多东西了Q我想休息一下,l大家说一个有的事情Q我们说了好多命令和目录的名子,你们是不是觉得有点奇怪。说实在话,我第一ơ看到usrq个目录时也不知道是什么意思,后来才发C下对应关p:
usr ->; user
ls ->; list
mkdir ->; make dir
rm ->; remove
src ->; source
mv ->; move
cp ->; copy
?
是不是很有趣Q在UNIX世界Q包括Linux世界Qh们的惌力就是这么无敌!写居然能写成q样子。大家一般的x是取一个单词的前三个或者前四个字母作ؓ写,可是UNIX的牛人就是喜Ƣ把move写成为mvQ真不知道他们怎么想的。大家一h摸吧
4. nano ?vi~辑文g的命??cat 以及 more昄文本文g
nano是一个小巧自由,q且友好的编辑器Q我认ؓnano更适合初学Linux的朋友用。我们现在只学习怎样~辑一个文件以及怎样保存?
nano 文g?
如果你写的文件名已经存在Q那么就打开q且~辑Q否则就建立一个新的文件。编辑的Ҏq用说吗Q呵呵,当你惌退出的时候,按ctrl+xQnano会问你是不是保存~辑的文件。按Y是保存Q按N׃保存?
nano最大好处在于用户可以不用记忆太多的操作键,大部分常用的功能的操作方法都在屏q下攑ֈZ。新手需要注意的是“^X”就是按住ctrl键不攑ֆ按X的意思?
下面单的介绍vi。vi是一个非常强大的~辑软g。它太庞大了Q够写一本书专门来讲解。我们这里从使用的角度出发,讲一下vi的用法?
vi有两U模式,一U是命o模式Q一U是~辑模式。进入vi以后Q默认处于命令模式?
现在我们执行vi LoveLetter。进入以后,按一下键盘上的Insert功能键或者i键可以进入编辑状态,可以插入字符Q再按一下Insert变成复盖模式Q这两种模式的区别很Ҏ体现Q大家尝试一下就可以了。上下左叛_个方向键可以Ud光标。基本的~辑命o和Windows里面没有区别。是不是很容易呢Q当你把需要的内容输入完成以后Q我们要保存Q这时候按一下ESC键从~辑模式回到命o模式Q首先输入一个冒号?”,也就是按住SHIFT键不攑ֆ按分号?”这样首先输入一个?”,然后Q输入wQ回车,可以保存我们编辑的内容到LoveLetter文g。现在我们按一下Insert可以l编辑。再按ESCQ输入?”,再按w又可以保存。可是现在我们不需要保存,我们惌不保存就退出,怎么做呢Q当我们输入w的时候是write的意思,保存Q那么我们输入q是quit退出的意思。好Q输入qQ回车,vi提示我们刚才q行的修改还没有保存Q所以记住!一旦需要放弃我们的修改Q不能直接用q命o退出,而需要用“q!”命令。输入q!Q好了,退Z?
我们想看看我们刚才编辑的LoveLetter是不是真的保存好了,再vi LoveLetterQokQ看C吧?现在我们惌直接退出,可以只输入?q”就可以了,不用输入那个?”因为我们没有修Ҏ件内宏V如果我们修改一下这文章,我们在退出的时候可以输入“ESC : wq”就可以了。不需要把w和q分成两次输入?
vi的最最基本用法说到q里差不多了Q要是你q想多了解一些vi的知识,在进入vi以后直接按F1可以了Q有详悉的帮助和教学?
其实刚才我们惌看一下编辑的LoveLetter是不是保存好了,不用再viq去的,只需要用命o
cat LoveLetter
可以了。cat是用来昄文本文g内容的命令。如果我们的文本文g很长Q一个屏q显CZ完,cat是不会自动分늚。我们可以换用命?
more LoveLetter
more命o昄文本文gӞ如果内容q多Q会自动的在每一늻束时暂停下来Q等到用h一下空格键再l?
5. 最重要的命令:halt reboot x和重新启动命?
在Linux里面Q不能够直接用电源按钮关机,也不能直接用reset按钮重新启动Q这对系l,其是硬盘有比较大的影响。关机命令是haltQ重启动命o是reboot。其实还有shutdown命o完成cM功能Q需要的话,L今天学会的man命o学习使用?br />
]]>
]]>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>无标题文?lt;/title>
</head>
<body>
<p>
<object id="player" style="display:none" height="400" width="400" classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6">
<param name="invokeURLs" value="-1">
<param NAME="AutoStart" VALUE="-1">
<param name="currentPosition" value="0">
<param name='uiMode' value='mini'>
<param NAME="url" VALUE="test.mpg">
</object>
</p>
<input name="submit" type="submit" onclick="getInfo()">
<p>
<script language="javascript">
var time;
function getInfo(){
var pl=document.getElementById("player");
time=pl.currentMedia.durationString;
alert(parseInt(pl.currentMedia.durationString.substring(0,2)*60));
//alert(parseInt(pl.currentMedia.durationString.substring(3,5)));
alert(parseInt(pl.currentMedia.durationString.substring(0,2)*60)+parseInt(pl.currentMedia.durationString.substring(3,5)));
}
</script>
</p>
</body>
</html>
Z么用EJB我原先认不是一个讨论的话题Q因为EJB是J2EE重要的组成部分,可以说没有EJB的J2EE只是一UWebpȝQ这Lpȝ非常Ҏ丧失了多层结构的大部分优点(仔细x那些混合多种层次功能JavaBeans和传l两层结构有什么区别?Q?/p>
当然Q可以h为地在Javabeans之间q行层次划分Q例如Hibernate数据持久层Q某些JavaBeans是业务核心层Q但是因为都是普通JavaBeansQ这U划分没有一U强制性和明显标志性,q样的系l更换了d人员或设计师Q可能就会被新的E序员修改得非常混ؕ?/p>
我们先看看一个包含EJB的J2EEpȝ是如何清晰地表达层次。如下图Q?/p>
Web完全只是一个MVC模式的实玎ͼ关键业务核心是在EJB的服务层实现Q这样做的优ҎQWeb只负责界面相关部分,因ؓQ如果是一个智能客LQ如Swing或J2MEQ在不需要修改Q何业务核心的情况下能够方便地更换。同P提供Web Services功能Q也只是?Web层修改,不会涉及EJB斚w的修改,同样保证了系l的E_性,保证了系l升U和未来的扩展性?/p>
如果不用EJBQ在EJB服务层实现的业务核心由普通JavaBeans实现Q用何U架构或设计能够保证负责MVC的JavaBeans和负责业务核心的JavaBeans清晰地分开Q又如何保证在新的程序员不会破坏和打׃_ֿ布局的JavaBeans架构Q?/p>
最主要的是性能问题Q由于以前国内中文Java|站有些人弯曲EJBQ认为EJB性能低,其实q是一U非常肤错误的认识Q我们首先看看在一般Java环境中是如何提高性能?/p>
假定一个JavaBeans为AQ那么一般用这个JavaBeans命o如下Q?/p>
A a = new A();
但是Q在高访问量的环境中Qnew A()其实是很Ҏ消耗系l性能的,因此Q能不能在Y件系l启动时候就预先建立一些对象,q样Q系l运行时Q从q些已经生成的对象池中借用一个,q样Q就无需在用时q行NewQ节U了开销Q提高了性能Q因此,真正成熟性能解决Ҏ都是需要对象池{支持?/p>
在一个纯Webl构的系l(也就是只能运行在Tomat环境中)Q例如Struts + Hibernate{这LpȝQ除非自己动手做Q一般是没有对象池技术支持的Q因此他们的性能只能是Demo演示版本的性能Q根本无法承受大定wq发讉KQ也无法UCؓ一个成熟的pȝQ所以,我们研究成熟的开源WebpȝQ如Jive、OFBizeQLifeRay{,他们都在Web层拥有自q对象池和~存池?/p>
对象池和~存机制是J2EE必须的吗Q当Ӟ是所有成熟系l必ȝQWindowspȝ如果L~存会变得怎样Q?/p>
自己动手开发对象池和缓存机制ƈ不是一件简单的事情Q需要对多线E以及同步锁{底层原理有深层ơ的把握Q这其实也是一门非常深入的Java研究分支Q所以,你可以抛开你的客户焦急的催促Q精心研I开发自q对象池和~存池?/p>
但是QEJB容器Q如JBossQ已l提供了对象池和~存机制Q所以,没有事务机制的无状态Session Bean的性能肯定要强于普通JavaBeans。EJB容器不但在单Z提供了对象池和缓存,而且可以跨服务器实现动态负载^衡,q些都无需开发者自己开发Q何Y件代码,l构如下Q?/p>
每一个jar包代表一个EJBlgQ一个系l可以由多个可重用的EJBlg构成Q例如:树Şl构EJBlgQ自增序号EJBlgQ用戯料EJBlg{,q样的EJBlg可以象积木一h配在大部分应用系l中Q提高了pȝ的开发效率,保证了开发质量?/p>
下图是某个新的具体系l时应用到的EJBlg图,在这个新的应用中Q由于用了以前大量可重用的EJBlgQ新的开发工作基本集中在界面设计和流E安排上Q?/p>
事务机制对于一些关键事务是很重要的Q例如ATM机提ƾ,提款有多个动作:修改数据库以及数qQ如果这其中有Q何一个环节出错,那么其它已经实现的操作必还原,否则Q就会出玎ͼ提款人没有拿到钱Q但是卡上已l扣Ƅ不可思议的事情发生?/p>
EJB提供的事务机刉常周全,但事务机制带来的~点是性能的降低,因此Q有些h认ؓEJB很重Q因为在实际应用中,有的用户pȝ可能不需要事务机Ӟ只是需要EJB提供的性能优化机制Q这P如果使用EJBQ就象叫一个h来背东西Q他除了背着我要的东西外Q还背着我不要的东西?/p>
除非你是一个完主义,在一般企业应用或数据库系l应用中QEJB不会对你构成很重的包袱?/p>
开源以及一些数据库持久层技术崇拜者,一直抨击CMPQ认为CMP慢无用,实际最大的问题是他们的设计和用问题?/p>
׃EJB容器Q如JBossQ对CMP实现有事务机制的~存优化Q因此,CMP特别适合多个用户同时更新同一个数据源的情况,CMPq种严格的事务完整性保证多个用户同时操作一个数据记录时Q能够保证性能优化和数据的完整性,如果q个数据记录是是软gpȝ的状态标志,它的状态会影响pȝ中很多的环节Q那么状态更改的重要性不a而喻?/p>
如果没有事务完整性支持,你的软gpȝ在用戯问量变大Q就会变得发生各U不可能发生的逻辑错误Q查看程序逻辑是正的Q那么问题出在哪里?出在数据完整性上?/p>
׃每个CMP在内存中都有一个缓存,在实际应用中Q如果用CMP扚wL据库数据Q几万条查询完毕Q内存中充满了几万条CMP~存Q如果这时你的EJB容器讄不当Q如使用JBoss~省配置Q,那么JVM的垃圑֛收机制就会频J启动,D你的pȝ变慢甚至LQ这也是一些h抨击CMP慢的原因所在,其实他们使用Ҏ不当Q或者没有正配|EJB容器CMP~存?/p>
对于q种情况Q根据J2EE核心模式Q推荐用DAO+JDBC方式?/p>
除非你对设计模式非常_深Q能够将自己pȝ中的JavaBeans使用模式或某U框架进行固定分层,同时Q你孜孜不倦研发出对象池,又熟l于JTA{事务机Ӟ你可以选择没有EJB的纯Webl构Q就象Jive、OFBiz那样。当然还有一个前提,老板不懂或者非常有挑战性(做与IBM SUN 微Y齐名的公司和技术)?/p>
不要再被TSS那些狂热的开源先生误|他们有时间有保障可以做他们喜Ƣ的事情Q作Z业的J2EEE序员,按照J2EE标准d习去行动Q也不要认ؓQ只要用了J2EE其中某个技术如Jsp或JavaBeans心安理得认qpȝ是J2EE了?/p>
当然Q我q不是说UWebpȝ不能实现多层l构Q但是至在很多斚w没有Web+EJBl构完善和清晎ͼ所以,EJB不是J2EE可以忽视的部分,而是主要的重要的部分Q重要业务功能核心都装在EJB中,相反Web层是一U次要的、和界面相关的层ơ?/p>
补充Q什么情况下不需要EJBQ在SUN的SECA架构师试卷中回答Q小型系l和不需要事务。另外过去那U认为“EJB有性能问题”根本是一U缪误,具体可参考下面有关问题?/p>
/**
* @author gongyifeng
*
* 更改所生成cd注释的模板ؓ
* H口 > 首选项 > Java > 代码生成 > 代码和注?br /> */
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletException;
// Referenced classes of package com.jspsmart.upload:
// SmartUploadException, SmartUpload
public class File{
private SmartUpload m_parent;
private int m_startData;
private int m_endData;
private int m_size;
private String m_fieldname;
private String m_filename;
private String m_fileExt;
private String m_filePathName;
private String m_contentType;
private String m_contentDisp;
private String m_typeMime;
private String m_subTypeMime;
private String m_contentString;
private boolean m_isMissing;
public static final int SAVEAS_AUTO = 0;
public static final int SAVEAS_VIRTUAL = 1;
public static final int SAVEAS_PHYSICAL = 2;
File(){
m_startData = 0;
m_endData = 0;
m_size = 0;
m_fieldname = new String();
m_filename = new String();
m_fileExt = new String();
m_filePathName = new String();
m_contentType = new String();
m_contentDisp = new String();
m_typeMime = new String();
m_subTypeMime = new String();
m_contentString = new String();
m_isMissing = true;
}
public void saveAs(String s) throws IOException, SmartUploadException{
saveAs(s, 0);
}
public void saveAs(String s, int i) throws IOException, SmartUploadException{
String s1 = new String();
s1 = m_parent.getPhysicalPath(s, i);
if(s1 == null)
throw new IllegalArgumentException("There is no specified destination file (1140).");
try
{
java.io.File file = new java.io.File(s1);
FileOutputStream fileoutputstream = new FileOutputStream(file);
fileoutputstream.write(m_parent.m_binArray, m_startData, m_size);
fileoutputstream.close();
}
catch(IOException ioexception)
{
throw new SmartUploadException("File can't be saved (1120).");
}
}
public void fileToField(ResultSet resultset, String s) throws ServletException, IOException, SmartUploadException, SQLException{
long l = 0L;
int i = 0x10000;
int j = 0;
int k = m_startData;
if(resultset == null)
throw new IllegalArgumentException("The RecordSet cannot be null (1145).");
if(s == null)
throw new IllegalArgumentException("The columnName cannot be null (1150).");
if(s.length() == 0)
throw new IllegalArgumentException("The columnName cannot be empty (1155).");
l = BigInteger.valueOf(m_size).divide(BigInteger.valueOf(i)).longValue();
j = BigInteger.valueOf(m_size).mod(BigInteger.valueOf(i)).intValue();
try
{
for(int i1 = 1; (long)i1 < l; i1++)
{
resultset.updateBinaryStream(s, new ByteArrayInputStream(m_parent.m_binArray, k, i), i);
k = k != 0 ? k : 1;
k = i1 * i + m_startData;
}
if(j > 0)
resultset.updateBinaryStream(s, new ByteArrayInputStream(m_parent.m_binArray, k, j), j);
}catch(SQLException sqlexception){
byte abyte0[] = new byte[m_size];
System.arraycopy(m_parent.m_binArray, m_startData, abyte0, 0, m_size);
resultset.updateBytes(s, abyte0);
}catch(Exception exception)
{
throw new SmartUploadException("Unable to save file in the DataBase (1130).");
}
}
public boolean isMissing(){
return m_isMissing;
}
public String getFieldName(){
return m_fieldname;
}
public String getFileName(){
DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
String date = df.format(new Date());
return date+m_filename;
}
public String getFilePathName(){
return m_filePathName;
}
public String getFileExt(){
return m_fileExt;
}
public String getContentType(){
return m_contentType;
}
public String getContentDisp(){
return m_contentDisp;
}
public String getContentString(){
String s = new String(m_parent.m_binArray, m_startData, m_size);
return s;
}
public String getTypeMIME() throws IOException{
return m_typeMime;
}
public String getSubTypeMIME(){
return m_subTypeMime;
}
public int getSize(){
return m_size;
}
protected int getStartData(){
return m_startData;
}
protected int getEndData(){
return m_endData;
}
protected void setParent(SmartUpload smartupload){
m_parent = smartupload;
}
protected void setStartData(int i){
m_startData = i;
}
protected void setEndData(int i){
m_endData = i;
}
protected void setSize(int i){
m_size = i;
}
protected void setIsMissing(boolean flag){
m_isMissing = flag;
}
protected void setFieldName(String s){
m_fieldname = s;
}
protected void setFileName(String s){
m_filename = s;
}
protected void setFilePathName(String s){
m_filePathName = s;
}
protected void setFileExt(String s){
m_fileExt = s;
}
protected void setContentType(String s){
m_contentType = s;
}
protected void setContentDisp(String s){
m_contentDisp = s;
}
protected void setTypeMIME(String s){
m_typeMime = s;
}
protected void setSubTypeMIME(String s){
m_subTypeMime = s;
}
public byte getBinaryData(int i){
if(m_startData + i > m_endData)
throw new ArrayIndexOutOfBoundsException("Index Out of range (1115).");
if(m_startData + i <= m_endData)
return m_parent.m_binArray[m_startData + i];
else
return 0;
}
}
Filesc?br />/*
* 创徏日期 2006-7-29
*
* 更改所生成文g模板?br /> * H口 > 首选项 > Java > 代码生成 > 代码和注?br /> */
package com.kinstar.issuing.file;
/**
* @author gongyifeng
*
* 更改所生成cd注释的模板ؓ
* H口 > 首选项 > Java > 代码生成 > 代码和注?br /> */
import java.io.IOException;
import java.util.*;
// Referenced classes of package com.jspsmart.upload:
// File, SmartUpload
public class Files{
private SmartUpload m_parent;
private Hashtable m_files;
private int m_counter;
Files(){
m_files = new Hashtable();
m_counter = 0;
}
protected void addFile(File file){
if(file == null)
{
throw new IllegalArgumentException("newFile cannot be null.");
} else {
m_files.put(new Integer(m_counter), file);
m_counter++;
return;
}
}
public File getFile(int i)
{
if(i < 0)
throw new IllegalArgumentException("File's index cannot be a negative value (1210).");
File file = (File)m_files.get(new Integer(i));
if(file == null)
throw new IllegalArgumentException("Files' name is invalid or does not exist (1205).");
else
return file;
}
public int getCount()
{
return m_counter;
}
public long getSize() throws IOException
{
long l = 0L;
for(int i = 0; i < m_counter; i++)
l += getFile(i).getSize();
return l;
}
public Collection getCollection()
{
return m_files.values();
}
public Enumeration getEnumeration()
{
return m_files.elements();
}
}
Requestc?br />/*
* 创徏日期 2006-7-29
*
* 更改所生成文g模板?br /> * H口 > 首选项 > Java > 代码生成 > 代码和注?br /> */
package com.kinstar.issuing.file;
/**
* @author gongyifeng
*
* 更改所生成cd注释的模板ؓ
* H口 > 首选项 > Java > 代码生成 > 代码和注?br /> */
import java.util.Enumeration;
import java.util.Hashtable;
public class Request
{
private Hashtable m_parameters;
private int m_counter;
Request(){
m_parameters = new Hashtable();
m_counter = 0;
}
protected void putParameter(String s, String s1) {
if(s == null)
throw new IllegalArgumentException("The name of an element cannot be null.");
if(m_parameters.containsKey(s))
{
Hashtable hashtable = (Hashtable)m_parameters.get(s);
hashtable.put(new Integer(hashtable.size()), s1);
} else{
Hashtable hashtable1 = new Hashtable();
hashtable1.put(new Integer(0), s1);
m_parameters.put(s, hashtable1);
m_counter++;
}
}
public String getParameter(String s){
if(s == null)
throw new IllegalArgumentException("Form's name is invalid or does not exist (1305).");
Hashtable hashtable = (Hashtable)m_parameters.get(s);
if(hashtable == null)
return null;
else
return (String)hashtable.get(new Integer(0));
}
public Enumeration getParameterNames()
{
return m_parameters.keys();
}
public String[] getParameterValues(String s)
{
if(s == null)
throw new IllegalArgumentException("Form's name is invalid or does not exist (1305).");
Hashtable hashtable = (Hashtable)m_parameters.get(s);
if(hashtable == null)
return null;
String as[] = new String[hashtable.size()];
for(int i = 0; i < hashtable.size(); i++)
as[i] = (String)hashtable.get(new Integer(i));
return as;
}
}
SmartUploadc?br />/*
* 创徏日期 2006-7-29
*
* 更改所生成文g模板?br /> * H口 > 首选项 > Java > 代码生成 > 代码和注?br /> */
package com.kinstar.issuing.file;
/**
* @author gongyifeng
*
* 更改所生成cd注释的模板ؓ
* H口 > 首选项 > Java > 代码生成 > 代码和注?br /> */
import java.io.*;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Vector;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
// Referenced classes of package com.jspsmart.upload:
// Files, Request, SmartUploadException, File
public class SmartUpload
{
protected byte m_binArray[];
protected HttpServletRequest m_request;
protected HttpServletResponse m_response;
protected ServletContext m_application;
private int m_totalBytes;
private int m_currentIndex;
private int m_startData;
private int m_endData;
private String m_boundary;
private long m_totalMaxFileSize;
private long m_maxFileSize;
private Vector m_deniedFilesList;
private Vector m_allowedFilesList;
private boolean m_denyPhysicalPath;
private boolean m_forcePhysicalPath;
private String m_contentDisposition;
public static final int SAVE_AUTO = 0;
public static final int SAVE_VIRTUAL = 1;
public static final int SAVE_PHYSICAL = 2;
private Files m_files;
private Request m_formRequest;
public SmartUpload()
{
m_totalBytes = 0;
m_currentIndex = 0;
m_startData = 0;
m_endData = 0;
m_boundary = new String();
m_totalMaxFileSize = 0L;
m_maxFileSize = 0L;
m_deniedFilesList = new Vector();
m_allowedFilesList = new Vector();
m_denyPhysicalPath = false;
m_forcePhysicalPath = false;
m_contentDisposition = new String();
m_files = new Files();
m_formRequest = new Request();
}
public final void init(ServletConfig servletconfig) throws ServletException
{
m_application = servletconfig.getServletContext();
}
public void service(HttpServletRequest httpservletrequest, HttpServletResponse httpservletresponse)throws ServletException, IOException
{
m_request = httpservletrequest;
m_response = httpservletresponse;
}
public final void initialize(ServletConfig servletconfig, HttpServletRequest httpservletrequest, HttpServletResponse httpservletresponse)throws ServletException
{
m_application = servletconfig.getServletContext();
m_request = httpservletrequest;
m_response = httpservletresponse;
}
public final void initialize(PageContext pagecontext)throws ServletException
{
m_application = pagecontext.getServletContext();
m_request = (HttpServletRequest)pagecontext.getRequest();
m_response = (HttpServletResponse)pagecontext.getResponse();
}
public final void initialize(ServletContext servletcontext, HttpSession httpsession, HttpServletRequest httpservletrequest, HttpServletResponse httpservletresponse, JspWriter jspwriter) throws ServletException
{
m_application = servletcontext;
m_request = httpservletrequest;
m_response = httpservletresponse;
}
public void upload()throws ServletException, IOException, SmartUploadException
{
int i = 0;
boolean flag = false;
long l = 0L;
boolean flag1 = false;
String s = new String();
String s2 = new String();
String s4 = new String();
String s5 = new String();
String s6 = new String();
String s7 = new String();
String s8 = new String();
String s9 = new String();
String s10 = new String();
boolean flag2 = false;
m_totalBytes = m_request.getContentLength();
m_binArray = new byte[m_totalBytes];
int j;
for(; i < m_totalBytes; i += j)
try
{
m_request.getInputStream();
j = m_request.getInputStream().read(m_binArray, i, m_totalBytes - i);
}
catch(Exception exception)
{
throw new SmartUploadException("Unable to upload.");
}
for(; !flag1 && m_currentIndex < m_totalBytes; m_currentIndex++)
if(m_binArray[m_currentIndex] == 13)
flag1 = true;
else
m_boundary = m_boundary + (char)m_binArray[m_currentIndex];
if(m_currentIndex == 1)
return;
for(m_currentIndex++; m_currentIndex < m_totalBytes; m_currentIndex = m_currentIndex + 2)
{
String s1 = getDataHeader();
m_currentIndex = m_currentIndex + 2;
boolean flag3 = s1.indexOf("filename") > 0;
String s3 = getDataFieldValue(s1, "name");
if(flag3)
{
s6 = getDataFieldValue(s1, "filename");
s4 = getFileName(s6);
s5 = getFileExt(s4);
s7 = getContentType(s1);
s8 = getContentDisp(s1);
s9 = getTypeMIME(s7);
s10 = getSubTypeMIME(s7);
}
getDataSection();
if(flag3 && s4.length() > 0)
{
if(m_deniedFilesList.contains(s5))
throw new SecurityException("The extension of the file is denied to be uploaded (1015).");
if(!m_allowedFilesList.isEmpty() && !m_allowedFilesList.contains(s5))
throw new SecurityException("The extension of the file is not allowed to be uploaded (1010).");
if(m_maxFileSize > 0L && (long)((m_endData - m_startData) + 1) > m_maxFileSize)
throw new SecurityException("Size exceeded for this file : " + s4 + " (1105).");
l += (m_endData - m_startData) + 1;
if(m_totalMaxFileSize > 0L && l > m_totalMaxFileSize)
throw new SecurityException("Total File Size exceeded (1110).");
}
if(flag3)
{
com.kinstar.issuing.file.File file = new com.kinstar.issuing.file.File();
file.setParent(this);
file.setFieldName(s3);
file.setFileName(s4);
file.setFileExt(s5);
file.setFilePathName(s6);
file.setIsMissing(s6.length() == 0);
file.setContentType(s7);
file.setContentDisp(s8);
file.setTypeMIME(s9);
file.setSubTypeMIME(s10);
if(s7.indexOf("application/x-macbinary") > 0)
m_startData = m_startData + 128;
file.setSize((m_endData - m_startData) + 1);
file.setStartData(m_startData);
file.setEndData(m_endData);
m_files.addFile(file);
} else
{
String s11 = new String(m_binArray, m_startData, (m_endData - m_startData) + 1);
m_formRequest.putParameter(s3, s11);
}
if((char)m_binArray[m_currentIndex + 1] == '-')
break;
}
}
public int save(String s)throws ServletException, IOException, SmartUploadException
{
return save(s, 0);
}
public int save(String s, int i)throws ServletException, IOException, SmartUploadException
{
int j = 0;
if(s == null)
s = m_application.getRealPath("/");
if(s.indexOf("/") != -1)
{
if(s.charAt(s.length() - 1) != '/')
s = s + "/";
} else
if(s.charAt(s.length() - 1) != '\\')
s = s + "\\";
for(int k = 0; k < m_files.getCount(); k++)
if(!m_files.getFile(k).isMissing())
{
m_files.getFile(k).saveAs(s + m_files.getFile(k).getFileName(), i);
j++;
}
return j;
}
public int getSize()
{
return m_totalBytes;
}
public byte getBinaryData(int i)
{
byte byte0;
try
{
byte0 = m_binArray[i];
}
catch(Exception exception)
{
throw new ArrayIndexOutOfBoundsException("Index out of range (1005).");
}
return byte0;
}
public Files getFiles()
{
return m_files;
}
public Request getRequest()
{
return m_formRequest;
}
public void downloadFile(String s) throws ServletException, IOException, SmartUploadException
{
downloadFile(s, null, null);
}
public void downloadFile(String s, String s1) throws ServletException, IOException, SmartUploadException, SmartUploadException
{
downloadFile(s, s1, null);
}
public void downloadFile(String s, String s1, String s2)throws ServletException, IOException, SmartUploadException
{
downloadFile(s, s1, s2, 65000);
}
public void downloadFile(String s, String s1, String s2, int i)throws ServletException, IOException, SmartUploadException
{
if(s == null)
throw new IllegalArgumentException("File '" + s + "' not found (1040).");
if(s.equals(""))
throw new IllegalArgumentException("File '" + s + "' not found (1040).");
if(!isVirtual(s) && m_denyPhysicalPath)
throw new SecurityException("Physical path is denied (1035).");
if(isVirtual(s))
s = m_application.getRealPath(s);
java.io.File file = new java.io.File(s);
FileInputStream fileinputstream = new FileInputStream(file);
long l = file.length();
boolean flag = false;
int k = 0;
byte abyte0[] = new byte[i];
if(s1 == null)
m_response.setContentType("application/x-msdownload");
else
if(s1.length() == 0)
m_response.setContentType("application/x-msdownload");
else
m_response.setContentType(s1);
m_response.setContentLength((int)l);
m_contentDisposition = m_contentDisposition != null ? m_contentDisposition : "attachment;";
if(s2 == null)
m_response.setHeader("Content-Disposition", m_contentDisposition + " filename=" + getFileName(s));
else
if(s2.length() == 0)
m_response.setHeader("Content-Disposition", m_contentDisposition);
else
m_response.setHeader("Content-Disposition", m_contentDisposition + " filename=" + s2);
while((long)k < l)
{
int j = fileinputstream.read(abyte0, 0, i);
k += j;
m_response.getOutputStream().write(abyte0, 0, j);
}
fileinputstream.close();
}
public void downloadField(ResultSet resultset, String s, String s1, String s2) throws ServletException, IOException, SQLException
{
if(resultset == null)
throw new IllegalArgumentException("The RecordSet cannot be null (1045).");
if(s == null)
throw new IllegalArgumentException("The columnName cannot be null (1050).");
if(s.length() == 0)
throw new IllegalArgumentException("The columnName cannot be empty (1055).");
byte abyte0[] = resultset.getBytes(s);
if(s1 == null)
m_response.setContentType("application/x-msdownload");
else
if(s1.length() == 0)
m_response.setContentType("application/x-msdownload");
else
m_response.setContentType(s1);
m_response.setContentLength(abyte0.length);
if(s2 == null)
m_response.setHeader("Content-Disposition", "attachment;");
else
if(s2.length() == 0)
m_response.setHeader("Content-Disposition", "attachment;");
else
m_response.setHeader("Content-Disposition", "attachment; filename=" + s2);
m_response.getOutputStream().write(abyte0, 0, abyte0.length);
}
public void fieldToFile(ResultSet resultset, String s, String s1)throws ServletException, IOException, SmartUploadException, SQLException
{
try
{
if(m_application.getRealPath(s1) != null)
s1 = m_application.getRealPath(s1);
InputStream inputstream = resultset.getBinaryStream(s);
FileOutputStream fileoutputstream = new FileOutputStream(s1);
int i;
while((i = inputstream.read()) != -1)
fileoutputstream.write(i);
fileoutputstream.close();
}
catch(Exception exception)
{
throw new SmartUploadException("Unable to save file from the DataBase (1020).");
}
}
private String getDataFieldValue(String s, String s1)
{
String s2 = new String();
String s3 = new String();
int i = 0;
boolean flag = false;
boolean flag1 = false;
boolean flag2 = false;
s2 = s1 + "=" + '"';
i = s.indexOf(s2);
if(i > 0)
{
int j = i + s2.length();
int k = j;
s2 = "\"";
int l = s.indexOf(s2, j);
if(k > 0 && l > 0)
s3 = s.substring(k, l);
}
return s3;
}
private String getFileExt(String s)
{
String s1 = new String();
int i = 0;
int j = 0;
if(s == null)
return null;
i = s.lastIndexOf(46) + 1;
j = s.length();
s1 = s.substring(i, j);
if(s.lastIndexOf(46) > 0)
return s1;
else
return "";
}
private String getContentType(String s)
{
String s1 = new String();
String s2 = new String();
int i = 0;
boolean flag = false;
s1 = "Content-Type:";
i = s.indexOf(s1) + s1.length();
if(i != -1)
{
int j = s.length();
s2 = s.substring(i, j);
}
return s2;
}
private String getTypeMIME(String s)
{
String s1 = new String();
int i = 0;
i = s.indexOf("/");
if(i != -1)
return s.substring(1, i);
else
return s;
}
private String getSubTypeMIME(String s)
{
String s1 = new String();
int i = 0;
boolean flag = false;
i = s.indexOf("/") + 1;
if(i != -1)
{
int j = s.length();
return s.substring(i, j);
} else
{
return s;
}
}
private String getContentDisp(String s)
{
String s1 = new String();
int i = 0;
int j = 0;
i = s.indexOf(":") + 1;
j = s.indexOf(";");
s1 = s.substring(i, j);
return s1;
}
private void getDataSection()
{
boolean flag = false;
String s = new String();
int i = m_currentIndex;
int j = 0;
int k = m_boundary.length();
m_startData = m_currentIndex;
m_endData = 0;
while(i < m_totalBytes)
if(m_binArray[i] == (byte)m_boundary.charAt(j))
{
if(j == k - 1)
{
m_endData = ((i - k) + 1) - 3;
break;
}
i++;
j++;
} else
{
i++;
j = 0;
}
m_currentIndex = m_endData + k + 3;
}
private String getDataHeader()
{
int i = m_currentIndex;
int j = 0;
boolean flag = false;
for(boolean flag1 = false; !flag1;)
if(m_binArray[m_currentIndex] == 13 && m_binArray[m_currentIndex + 2] == 13)
{
flag1 = true;
j = m_currentIndex - 1;
m_currentIndex = m_currentIndex + 2;
} else
{
m_currentIndex++;
}
String s = new String(m_binArray, i, (j - i) + 1);
return s;
}
private String getFileName(String s)
{
String s1 = new String();
String s2 = new String();
int i = 0;
boolean flag = false;
boolean flag1 = false;
boolean flag2 = false;
i = s.lastIndexOf(47);
if(i != -1)
return s.substring(i + 1, s.length());
i = s.lastIndexOf(92);
if(i != -1)
return s.substring(i + 1, s.length());
else
return s;
}
public void setDeniedFilesList(String s) throws ServletException, IOException, SQLException
{
String s1 = "";
if(s != null)
{
String s2 = "";
for(int i = 0; i < s.length(); i++)
if(s.charAt(i) == ',')
{
if(!m_deniedFilesList.contains(s2))
m_deniedFilesList.addElement(s2);
s2 = "";
} else
{
s2 = s2 + s.charAt(i);
}
if(s2 != "")
m_deniedFilesList.addElement(s2);
} else
{
m_deniedFilesList = null;
}
}
public void setAllowedFilesList(String s)
{
String s1 = "";
if(s != null)
{
String s2 = "";
for(int i = 0; i < s.length(); i++)
if(s.charAt(i) == ',')
{
if(!m_allowedFilesList.contains(s2))
m_allowedFilesList.addElement(s2);
s2 = "";
} else
{
s2 = s2 + s.charAt(i);
}
if(s2 != "")
m_allowedFilesList.addElement(s2);
} else
{
m_allowedFilesList = null;
}
}
public void setDenyPhysicalPath(boolean flag)
{
m_denyPhysicalPath = flag;
}
public void setForcePhysicalPath(boolean flag)
{
m_forcePhysicalPath = flag;
}
public void setContentDisposition(String s)
{
m_contentDisposition = s;
}
public void setTotalMaxFileSize(long l)
{
m_totalMaxFileSize = l;
}
public void setMaxFileSize(long l)
{
m_maxFileSize = l;
}
protected String getPhysicalPath(String s, int i)throws IOException
{
String s1 = new String();
String s2 = new String();
String s3 = new String();
boolean flag = false;
s3 = System.getProperty("file.separator");
if(s == null)
throw new IllegalArgumentException("There is no specified destination file (1140).");
if(s.equals(""))
throw new IllegalArgumentException("There is no specified destination file (1140).");
if(s.lastIndexOf("\\") >= 0)
{
s1 = s.substring(0, s.lastIndexOf("\\"));
s2 = s.substring(s.lastIndexOf("\\") + 1);
}
if(s.lastIndexOf("/") >= 0)
{
s1 = s.substring(0, s.lastIndexOf("/"));
s2 = s.substring(s.lastIndexOf("/") + 1);
}
s1 = s1.length() != 0 ? s1 : "/";
java.io.File file = new java.io.File(s1);
if(file.exists())
flag = true;
if(i == 0)
{
if(isVirtual(s1))
{
s1 = m_application.getRealPath(s1);
if(s1.endsWith(s3))
s1 = s1 + s2;
else
s1 = s1 + s3 + s2;
return s1;
}
if(flag)
{
if(m_denyPhysicalPath)
throw new IllegalArgumentException("Physical path is denied (1125).");
else
return s;
} else
{
throw new IllegalArgumentException("This path does not exist (1135).");
}
}
if(i == 1)
{
if(isVirtual(s1))
{
s1 = m_application.getRealPath(s1);
if(s1.endsWith(s3))
s1 = s1 + s2;
else
s1 = s1 + s3 + s2;
return s1;
}
if(flag)
throw new IllegalArgumentException("The path is not a virtual path.");
else
throw new IllegalArgumentException("This path does not exist (1135).");
}
if(i == 2)
{
if(flag)
if(m_denyPhysicalPath)
throw new IllegalArgumentException("Physical path is denied (1125).");
else
return s;
if(isVirtual(s1))
throw new IllegalArgumentException("The path is not a physical path.");
else
throw new IllegalArgumentException("This path does not exist (1135).");
} else
{
return null;
}
}
public void uploadInFile(String s)throws IOException, SmartUploadException
{
int i = 0;
int j = 0;
boolean flag = false;
if(s == null)
throw new IllegalArgumentException("There is no specified destination file (1025).");
if(s.length() == 0)
throw new IllegalArgumentException("There is no specified destination file (1025).");
if(!isVirtual(s) && m_denyPhysicalPath)
throw new SecurityException("Physical path is denied (1035).");
i = m_request.getContentLength();
m_binArray = new byte[i];
int k;
for(; j < i; j += k)
try
{
k = m_request.getInputStream().read(m_binArray, j, i - j);
}
catch(Exception exception)
{
throw new SmartUploadException("Unable to upload.");
}
if(isVirtual(s))
s = m_application.getRealPath(s);
try
{
java.io.File file = new java.io.File(s);
FileOutputStream fileoutputstream = new FileOutputStream(file);
fileoutputstream.write(m_binArray);
fileoutputstream.close();
}
catch(Exception exception1)
{
throw new SmartUploadException("The Form cannot be saved in the specified file (1030).");
}
}
private boolean isVirtual(String s)
{
if(m_application.getRealPath(s) != null)
{
java.io.File file = new java.io.File(m_application.getRealPath(s));
return file.exists();
} else
{
return false;
}
}
}
SmartUploadException c?br />/*
* 创徏日期 2006-7-29
*
* 更改所生成文g模板?br /> * H口 > 首选项 > Java > 代码生成 > 代码和注?br /> */
package com.kinstar.issuing.file;
/**
* @author gongyifeng
*
* 更改所生成cd注释的模板ؓ
* H口 > 首选项 > Java > 代码生成 > 代码和注?br /> */
public class SmartUploadException extends Exception
{
SmartUploadException(String s)
{
super(s);
}
}
上传的Servlet
package com.kinstar.issuing.action;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.*;
import java.sql.SQLException;
import java.util.*;
import java.text.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.kinstar.issuing.file.File;
import com.kinstar.issuing.file.SmartUpload;
import com.kinstar.issuing.objects.t_user;
import com.kinstar.issuing.operation.UserOperation;
import com.kinstar.issuing.program.programService;
import com.kinstar.issuing.session.SessionGloble;
import com.kinstar.issuing.util.StringUtil;
/**
* @version 1.0
* @author gyf
*/
public class upload2ProgramAction extends HttpServlet{
private ServletConfig config;
/**
* 初始化Servlet
*/
final public void init(ServletConfig config) throws ServletException {
this.config = config;
}
/**
* 处理GETh
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
/**
* 响应POSTh
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int count=0;
SmartUpload mySmartUpload = new SmartUpload();
try {
// 初始?br /> mySmartUpload.initialize(config,request,response);
// 上蝲
mySmartUpload.upload();
com.kinstar.issuing.file.File f1 = mySmartUpload.getFiles().getFile(0);
// com.kinstar.issuing.file.File f2 = mySmartUpload.getFiles().getFile(1);
String backPic = f1.getFileName();
//String name2 = f2.getFileName();
long size=0;
// 保存上蝲文g到指定目?br /> count=mySmartUpload.save("ads");
response.sendRedirect("program.jsp?dopass=ture");
}
catch (Exception e){
response.sendRedirect("fail.jsp");
}
}
2.common-fileuploadlg
挺好用的,也能够上传大文g,我试q?300M以上的文件上传本C非常?异地试也能够上传成?
首先要下载org.apache.commons.fileupload包和org.apache.commons.io?br />
下面是我的servlet
package com.kinstar.issuing.action;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.*;
import java.sql.SQLException;
import java.util.*;
import java.text.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.regex.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import com.kinstar.issuing.objects.t_user;
import com.kinstar.issuing.operation.UserOperation;
import com.kinstar.issuing.program.programService;
import com.kinstar.issuing.session.SessionGloble;
import com.kinstar.issuing.util.StringUtil;
/**
* @version 1.0
* @author gyf
*/
public class uploadProgramAction extends HttpServlet{
private static final String CONTENT_TYPE = "text/html; charset=GB2312";
/**
* 处理GETh
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
/**
* 响应POSTh
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 变量定义
response.setContentType(CONTENT_TYPE);
HttpSession modifysession=request.getSession();
SessionGloble logonUser;
logonUser=(SessionGloble)modifysession.getAttribute("UserInfo");
if(logonUser==null){
response.sendRedirect("mainindex.jsp");
}
t_user userinfo=new t_user();
UserOperation user=null;
try {
user = new UserOperation();
} catch (Exception e1) {
// TODO 自动生成 catch ?br /> e1.printStackTrace();
}
try {
userinfo=user.getUser(logonUser.getUserId());
} catch (Exception e2) {
// TODO 自动生成 catch ?br /> e2.printStackTrace();
}
//System.out.println("figure="+userinfo.getUserFigure());
PrintWriter out=response.getWriter();
DateFormat updf = new SimpleDateFormat("yyyyMMddHHmm");
String updateTime = updf.format(new Date());
int isNeed = 0;
String IsCheck="0";
//省农行用户上传的节目必需昄Q且审批已经合格
if(userinfo.getUserFigure().equals("1")){
isNeed = 1;
IsCheck = "1";
}
else{
isNeed = 0;
IsCheck = "0";
}
int type=0;
String avaTime="";
String screen="";
int fileTime=0;
int fileTimeReal=0;
int circle=0;
String picSwitch="";
String deleState="1";
String backPic="";
String fieldName="";
String finalName="";
String fileNameReal="";
long size=0;
String name="";
try {
DiskFileUpload fu = new DiskFileUpload();
// 讄允许用户上传文g大小,单位:字节Q这里设?m
fu.setSizeMax(5*1024*1024*1024);
// 讄最多只允许在内存中存储的数?单位:字节
fu.setSizeThreshold(10*1024*1024);
// 讄一旦文件大超qgetSizeThreshold()的值时数据存放在硬盘的目录
fu.setRepositoryPath("C:\\WINDOWS\\Temp\\");
//开始读取上传信?br /> List fileItems = fu.parseRequest(request);
//依次处理每个上传的文?br /> Iterator iter = fileItems.iterator();
//正则匚wQ过滤\径取文g?br /> String regExp=".+\\\\(.+)$";
//qo掉的文gcd
String[] errorType={".exe",".com",".cgi",".asp"};
Pattern p = Pattern.compile(regExp);
StringUtil su = new StringUtil();
while (iter.hasNext()) {
FileItem item = (FileItem)iter.next();
if(item.isFormField()) {
// 获得表单域的名字
fieldName = item.getFieldName();
// 如果表单域的名字是name?
if(fieldName.equals("type"))
type = Integer.parseInt(item.getString());
}
if (!item.isFormField()) {
name = item.getName();
size = item.getSize();
if((name==null||name.equals("")) && size==0)
continue;
Matcher m = p.matcher(name);
boolean result = m.find();
if (result){
for (int temp=0;temp<errorType.length;temp++){
if (m.group(1).endsWith(errorType[temp])){
throw new IOException(name+": wrong type");
}
}
DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
String date = df.format(new Date());
fileNameReal=date+m.group(1);
finalName=date+Math.round(Math.random()*10000)+fileNameReal.substring(fileNameReal.indexOf("."));
//保存上传的文件到指定的目录 ?br /> //在下文中上传文gx据库Ӟ对q里改写
item.write(new File(getServletContext().getRealPath(".//ads//")+finalName));
//out.print(finalName+size);
}
else
{
throw new IOException("fail to upload");
}
}
if(item.isFormField()) {
// 获得表单域的名字
fieldName = item.getFieldName();
if(fieldName.equals("avaTime"))
avaTime=item.getString();
if(fieldName.equals("screen"))
screen=item.getString();
if(fieldName.equals("fileTime"))
fileTime = Integer.parseInt(item.getString());
if(fieldName.equals("fileTimeReal"))
fileTimeReal = Integer.parseInt(item.getString());
if(fieldName.equals("circle"))
circle = Integer.parseInt(item.getString());
if(fieldName.equals("switchPic"))
picSwitch = item.getString();
}
}
}catch (IOException e){
out.println(e);
}catch (FileUploadException e){
out.println(e);
} catch (Exception e) {
// TODO 自动生成 catch ?br /> e.printStackTrace();
}
if(finalName.equals("")){
response.sendRedirect("fail.jsp");
}
else{
try {
programService ps = new programService();
ps.insertProgram(userinfo.getUserId(),updateTime,type,finalName,size,isNeed,avaTime,deleState,IsCheck,userinfo.getCity(),backPic,screen,fileTime,fileTimeReal,picSwitch,circle,userinfo.getUserFigure(),new String(fileNameReal.getBytes("GB2312"),"ISO8859-1"));
response.sendRedirect("program.jsp?dopass=true");
} catch (Exception e3) {
// TODO 自动生成 catch ?br /> e3.printStackTrace();
}
}
}
}
如何在Web工程中实CQ务计划调?/font>
好多朋友用过Windows的Q务计划,也有不少E序q己曾写过旉报警、系l自动关机等味E序Q可却很有朋友在Web工程中实现过cM功能。今天有I把W者先前曾在Tomcat上实现的cM功能Q搬出来与大家共享?br /> 早在几年前,我公司跟某市财政局合作目开发,为加政局Ҏ属单位胦务状늚有效监管Q开发、实施了财政局数据中心目。此目采用B/S加C/S混合l构模式。胦政局Web服务器上架设数据同步接收装置Q由市属单位每天下班前把财务信息通过HTTP协议上传臌政局中心服务器,与Web服务器上的接收装|对接。胦政局内部各部门需要查阅大量胦务信息,获取完备的市属单位当前胦务状况信息,各部门按职能划分Q需要准的获取各部门各自所x的汇M息,以胦政报表的形式提供?
因胦政数据量大,实时计算财政报表速度较慢Q当初就考虑用报表缓存来减轻服务器的负担Q但用缓存需要一个合理的~存更新机制。考虑到各市属单位每天下班前才把胦务数据上传,财政局每天所查看到的财务信息其实q不包括当天Q除非有某位领导{到所属单位全部上传完之后才来查看信息Q应该已l下班了Q,所以要是能实现d计划调度Q在每晚深夜把当天及历史财务信息汇总,更新~存Q速度瓉不就解决了吗?br /> 当时׃pȝ核心是基于Web部v的,报表计算引擎也相应的部v在Tomcat容器上,因此如果惌借用Windows的Q务计划来实现定时计算Q就需要额外编写普通桌面应用程序接口,E显复杂。于是就琢磨着惛_Web上实玎ͼl过查阅较多相关资料Q发现Java定时器(java.util.TimerQ有定时触发计划d的功能,通过配置定时器的间隔旉Q在某一间隔旉D之后会自动有规律的调用预先所安排的计划Q务(java.util.TimerTaskQ。另外,׃我们希望当Web工程启动Ӟ定时器能自动开始计Ӟ在整个Web工程的生命期里,定时器能在每晚深夜触发一ơ报表计引擎。因此定时器的存放位|也值得考查Q不能简单的存在于单个Servlet或JavaBean中,必须能让定时器宿ȝ存活期ؓ整个Web工程生命期,在工E启动时能自动加载运行。结合这两点Q跟Servlet上下文有关的侦听器就最合适不q了Q通过在工E的配置文g中加以合理配|,会在工程启动时自动运行,q在整个工程生命期中处于监听状态?br /> 下面Servlet侦听器结合Java定时器来讲述整个实现q程。要q用Servlet侦听器需要实现javax.servlet.ServletContextListener接口Q同时实现它的contextInitialized(ServletContextEvent event)和contextDestroyed(ServletContextEvent event)两个接口函数。考虑定时器有个徏立和销毁的q程Q看了前面两个接口函敎ͼ׃容置疑的把徏立的q程|入contextInitializedQ把销毁的q程|入contextDestroyed了?br /> 我把ServletContextListener的实现类取名为ContextListener,在其内添加一个定时器Q示例代码如下所C(虑幅Q仅提供部分代码供读者参考)Q?/font>
private java.util.Timer timer = null;
public void contextInitialized(ServletContextEvent event) {
timer = new java.util.Timer(true);
event.getServletContext().log("定时器已启动");
timer.schedule(new MyTask(event.getServletContext()), 0, 60*60*1000);
event.getServletContext().log("已经dd调度?);
}
public void contextDestroyed(ServletContextEvent event) {
timer.cancel();
event.getServletContext().log("定时器销?);
}
以上代码? timer.schedule(new MyTask(event.getServletContext()), 0, 60*60*1000)q一行ؓ定时器调度语句,其中MyTask是自定义需要被调度的执行Q务(在我的胦政数据中心项目中是报表计算引擎入口Q,从java.util.TimerTaskl承Q下面会重点讲述Q第三个参数表示每小??0*60*1000毫秒)被触发一ơ,中间参数0表示无gq。其它代码相当简单,不再详细说明?br /> 下面介绍MyTask的实玎ͼ上面的代码中看到了在构造MyTaskӞ传入了javax.servlet.ServletContextcd参数,是ؓ记录Servlet日志方便而传入,因此需要重载MyTask的构造函敎ͼ其父cjava.util.TimerTask原构造函数是没有参数的)。在timer.schedule()的调度中,讄了每时调度一?因此如果惛_现调度Q务每24时被执行一ơ,q需要判断一下时钟点Q以帔RC_SCHEDULE_HOUR表示(晚上12点,也即0?。同时ؓ防止24时执行下来QQ务还未执行完Q当Ӟ一般Q务是没有q么长的Q,避免W二ơ又被调度以引v执行冲突Q设|了当前是否正在执行的状态标志isRunning。示例代码如下所C:
private static final int C_SCHEDULE_HOUR = 0;
private static boolean isRunning = false;
private ServletContext context = null;
public MyTask(ServletContext context) {
this.context = context;
}
public void run() {
Calendar cal = Calendar.getInstance();
if (!isRunning) {
if (C_SCHEDULE_HOUR == cal.get(Calendar.HOUR_OF_DAY)) {
isRunning = true;
context.log("开始执行指定Q?);
//TODO d自定义的详细dQ以下只是示?
int i = 0;
while (i++ < 10) {
context.log("已完成Q务的" + i + "/" + 10);
}
isRunning = false;
context.log("指定d执行l束");
}
} else {
context.log("上一ơQ务执行还未结?);
}
}
上面代码中?/TODO……”之下四行是真正被调度执行的演示代码(在我的胦政数据中心项目中是报表计算q程)Q您可以换成自己希望执行的语句?br />到这儿,ServletContextListener和MyTask的代码都已完整了。最后一步就是把ServletContextListener部v到您的Web工程中去Q在您工E的web.xml配置文g中加入如下三行:
com.test.ContextListener
当然Q上面的com.test得换成您自己的包名了。保存web.xml文g后,把工E打包部|到Tomcat中即可。Q务会在每?2点至凌晨1点之间被执行Q上面的代码会在Tomcat的日志文件中记录如下Q?br />2003-12-05 0Q?1Q?9 开始执行指定Q?br />2003-12-05 0Q?1Q?9 已完成Q务的1/10
…?br />2003-12-05 0Q?1Q?9 已完成Q务的10/10
2003-12-05 0Q?1Q?9 指定d执行l束
public class SimpleAudioPlayer {
private Player audioPlayer = null;
术语Player听v来由点熟悉,因ؓ它是建立在我们公用的音频或者视频播攑֙的基上的。事实上Q这个接口的例子像是当作它们的真实的副本。Players揭示了一个实体上的媒体播攑֙Q如立体音箱pȝ或者VCRQ涉及到功能上的Ҏ。例如,一个JMF媒体播放器可以开始和l束一个媒体流。在本节U,我们用Player的开始和l束功能?br />
在一个文件上创徏一个Player
使用JMF获得一个特定媒体文件的Player实例非常单。ManagercdJMF中如同一个工厂制作许多的Ҏ接口cdQ包括Player接口。因此,Managercȝ责Q是创徏Player实例Q如下例Q?br />
public SimpleAudioPlayer(URL url) throws IOException,
NoPlayerException,
CannotRealizeException {
audioPlayer = Manager.createRealizedPlayer(url);
}
public SimpleAudioPlayer(File file) throws IOException,
NoPlayerException,
CannotRealizeException {
this(file.toURL());
}
如果你看完本节的代码Q你可以注意到Managercd含了创徏一个Player实例的其他方法。我们会研究其中的一些,如在后面的章节中的DataSource或者MediaLocator的实例化?br />
Player的状?/b>
JMF定义了大量的一个Player实例可能存在的不同状态。如下:
· Prefetched
· Prefetching
· Realized
· Realizing
· Started
· Unrealized
使用q些状?/b>
因ؓ使用媒体常常是资源非常密集的Q由JMF对象揭示的许多方法都是不闭塞的,允许一pd事g监听的状态改变的异步通知。例如,一个Player在它可以启动之前Q必ȝqPrefetched和Realized状态。由于这些状态的改变都需要一些时间来完成QJMF媒体应用可以分配一个线E来初始化创建Player实例Q然后再l箋其他的操作。当Player准备qA的时候,它会通知应用E序其状态已l改变?br />
在一个如同我们的q样单的E序中,多功能性的cdq不是很重要。处于这个原因,ManagercM提供了一些创建Realized player的有用方法。调用一个createRealizedPlayer()Ҏ来阻塞调用线E,直到player辑ֈRealized状态。ؓ了调用一个无d的创建player的方法,我们在ManagercM使用了一个createPlayer()Ҏ。下面的一行代码中创徏了一个我们需要在例程序中使用?br />
Realized playerQ?br />audioPlayer = Manager.createRealizedPlayer(url);
启动和停止Player
讑֮一个Player实例的启动或是停止就如同调用Player的一个简单的认证ҎQ如下所C:
public void play() {
audioPlayer.start();
}
public void stop() {
audioPlayer.stop();
audioPlayer.close();
}
调用SimpleAudioPlayercM的play()Ҏ来实现调用Player实例的start()Ҏ。调用此Ҏ后,你能听到本地的喇叭的声音文g。同LQstop()Ҏ使player停止q且关闭掉Player对象?br />
对于d和或者播放本地媒体文件来_关闭Player实例释放所有资源是一个有用的Ҏ。因是一个简单的例子Q关闭Player是终止一个会话可接受的方法。但是在实际的应用中Q你需要小心的认在除掉Player之前必须要关闭掉。一但你已经关闭掉playerQ在再次播放一个媒体之前你必须要创Z个新的Player实例Q等待它的状态改变)?br />
建立一个SimpleAudioPlayer
最后,q个媒体播放应用E序要包含一个可以从命o提示行中输入命o而调用的main()Ҏ。在此main()Ҏ中,我们调用创建SimpleAudioPlayer的方法:
File audioFile = new File(args[0]);
SimpleAudioPlayer player = new SimpleAudioPlayer(audioFile);
在播N频文件之前的唯一的一些事情就是调用已l创建的音频player的方法play()Q如下所C:
player.play();
要停止和清除掉音频playerQ在main()Ҏ中也应该有如下调用:
player.stop();
~译和运行SimpleAudioPlayer
通过在命令提C输入javac SimpleAudioPlayer.java来编译例E序。所创徏的文件SimpleAudioPlayer.class在当前工作目录中?br />然后在命令提C中键入如下命令来q行例程序:
java SimpleAudioPlayer audioFile
audioFile替换成你本地机器上的音频文g。所有的相对文g名都试相对于当前的工作目录。你会看C些当前正在播放文件的标志信息。要l止播放Q按下回车键?br />如果~译p|Q确认JMF的jar文g已经正确的包含在CLASSPATH环境变量中?br />
W三? JMF用户界面lg
播放视频
在前一节中Q我们学习了建立一个通过字符界面播放音频文g的应用程序。JMF中一个最重要的特点就是你不需要ؓ了配|媒体播攑֙而去了解媒体文g的格式;一切都内置了。D一个例子,再我们前面的例子中,需要用MP3格式的时候,我们不需要让应用E序Z个MP3文g建立一个特D的Player?br />如同你将会再本节所见到的,对于视频文g的操作同h效。JMF有所有媒体文件类型接口的详细资料?br />处理视频媒体与音频最大的不同是Q我们必d立一个能播放视频的显C屏q。幸q的是,JMF能处理许多的q些资料。如同再上例一h们会建立一个Player对象Qƈ且用很多的可视lg来直接从JMF对象中创建我们的可视的媒体浏览器?br />本节中,我们学习两个例E序。In this section, we'll walk through the second example application. 请再后面的练习的源代码分布中查阅MediaPlayerFrame.java?br />
关于例子
在本节中Q我们将创徏一个能昄和运行本地音频和视频媒体的应用程序。作为练习的一部分Q我们将研究JMF内置的一些GUIlg。熟悉AWT和Swing有助于你理解本例,但这q不是必ȝ。除非需要直接涉及到JMF的GUIlgQ或者我们是不会详细介绍源代码的。你可以在源代码的注释中扑ֈq里未涉及的详细说明?br />本例中我们用的许多概念Q类和方法都和第一个例子的cM。徏立Player的基本操作大都一栗最大的不同是我们需要对Player对象专研更深一点,特别当需要从Player获取媒体信息的时候?br />
如何开?/b>
视频播放器例子被设计得如同音频播放例子一样通过命o行来q行Q但是本例需要徏立在GUI基础上。如同在上节一P我们先通过媒体文g名调用应用。然后,应用E序昄一个带有可操作媒体lg的窗体?br />在MediaPlayerFrame开始的一行中我们定义了类q扩展自Qjavax.swing.JframecR这是使媒体播攑֙如同一个在桌面上的单独H体的方法。Q何客hE序创徏了本媒体播放对象后都可以通过调用JframecM定义的show()Ҏ来显C?br />下面是一个MediaPlayerFrame正在播放MPEG电媄的屏q截图:
获取GUIlg
Player界面有一些方法来获取已选择可视lg的涉及。在MediaPlayerFrame中,我们使用如下lgQ?br />· player.getVisualComponent()是一个播放所有视频媒体的可视lg?br />· player.getControlPanelComponent() 是一个操作时间u的可视组Ӟ包括开始,停止Q回放)Q也包含了一些媒体流的有用信息?br />· player.getGainControl().getControlComponent() 是操作音量(增加Q的可视lg。getGainControl()Ҏq回一个GainControl实例Q可用于改变节目的增加等U?br />
使用可视化组?/b>
上面的界面方法都q回一个java.awt.Componentcȝ实例。没个实例都视可加蝲到我们窗体上的可视组件。这些组仉与Player有直接的联系Q所以在q些lg上的所有可视元素的处理都会产生Player播放媒体后相应的变化?br />在我们将q些lg加入到我们的H体的之前,必须要保证它们不为空。因为ƈ不是所有的媒体播放器包括每一U可视组Ӟ我们只需d相关播放器类型的lg。比如,一般来说一个音频播攑֙没有可视lgQ所以getVisualComponent()pq回I。你不会惛_音频播放器窗体上d可视lg的?br />
获得媒体的特D控?/b>
一个Player实例也可以通过getControl()和getControls()Ҏ来暴露其控制QgetControls()q回一个控制对象集Q而getControl()q回一个控制。不同的播放器类型可选择为特D的操作来暴露控刉L定的媒体cdQ或者用于获取该媒体的传输机制。如果你在写一个只支持某些媒体cd的播攑֙Q你需要依靠某些在Player实例中可用Control对象?br />׃我们的播攑֙是非常抽象的Q被设计于播攑֤U不同媒体类型,我们单的为用h露所有的Control对象。如果找CQ何扩展的控制集,我们可使用getControlComponent()Ҏ来增加相应的可视控g到标{N板上。通过q个办法Q用户就可以观察播放器上的所有组件。以下代码片断将所有的控制对象暴露l用P
Control[] controls = player.getControls();
for (int i = 0; i < controls.length; i++) {
if (controls[i].getControlComponent() != null) {
tabPane.add(controls[i].getControlComponent());
}
}
Z使一个真实的应用E序能用Control实例做一些有用的事(除了能显C可视组件之外)Q应用程序需要知道该Control的特D类型,q分配它。此后,应用E序可使用q些control来控制媒体节目了。例如,如果你知道你l常使用的媒体暴露javax.media.control.QualityControlcd的ControlQ你能用QualityControl界面Q之后在QualityControl界面上通过调用各种Ҏ来改变性质讑֮?br />
使用一个MediaLocator
在我们新的基于GUI的媒体播攑֙和我们的W一个简单播攑֙之间最大的不同是Q我们用一个MediaLocator对象而不是URL来创建Player实例Q如下所C:
public void setMediaLocator(MediaLocator locator) throws IOException,
NoPlayerException, CannotRealizeException {
setPlayer(Manager.createRealizedPlayer(locator));
}
我们在E后的章节中讨论q个变化的原因。目前,在网l上资源站点上,关于MediaLocator对象和URL的描q被认ؓ是非常相似的。事实上Q你可以从一个URL创徏一个MediaLocatorQ也可以从MediaLocator获取到URL。我们的新媒体播攑֙一个URL中创Z个MediaLocatorQƈ使用该MediaLocator通过文g创徏了一个Player?br />
~译和运行MediaPlayerFrame
通过在命令提C输入javac MediaPlayerFrame.java来编译例E序。在工作目录下将创徏一个名为MediaPlayerFrame.class的文件?br />在命令提C中键入如下来q行例程序:
java MediaPlayerFrame mediaFile
你需要用你本Z的一个媒体文件来替换掉mediaFileQ音频或者视频文仉可以Q。所有的相对文g名都是相对于当前工作目录。你会看见一个显C控制媒体文件的GUI控制集的H口。欲了解JMF支持的音频和视频文g列表Q在23늚资源?br />如果初始~译时失败,L认JMF的jar文g已经包含在当前的CLASSPATH环境变量中?br />
MediaPlayerFrame在行?/b>
在本节前你看见的一个视频播攑֙正在播放MPEG视频文g的屏q截图。下面的屏幕截图昄了一个音频播攑֙正在播放一个MP3文gQ?br />要更多的学习本练习中的例子,查看完成的MediaPlayerFrame源代码?br />
W四? JMF概念
JMF体系l构
你曾见过了用JMF播放本地媒体文g是多么的ҎQ现在我们将后退一步,来看看一q是如何通过JMF创徏了如此成熟的Z媒体的应用程序的大的画面Q是如何通过JMF创徏了如此成熟的Z媒体的应用程序。全面的了解JMF体系l构是没有意义的Q本节将l你一个大体的概念Q关于高U的JMFlg是如何组合v来创建想得到的东ѝ?br />JMF的组件结构非常的灉|Q它的组件一般可以分成三个部分:
· Input描述某种被用于在q程休息的时候作Z个输入的媒体?br />· process执行某些输入上的zd。一个过E有一个明的输入和输出。大量的q程可用, 能被用于一个输入或者一批输入。这些过E能被联pv来,一个过E的输出被用于另外一个过E的输入。在q种风格中,大量的过E可能被应用于一个输入。(q段期间是可选择的——我们开始的两个例子没有包含真正的数据过E,只有一个来自文件的输入和一个通过Player的输出。)
· Output 描述了媒体的某些目的地?br />
从这些描qCQ你可以惌到JMFlg体系l构听v来就好像在一个典型的立体声系l或者VCR之后。很Ҏ设想刎ͼ使用JMF如同打开电视或者在立体声音ql下调节声音的风根{例如,录制喜爱的电视节目的单的动作能在q些lg的基中:
· Input 是电视广播流Q在同一个频道运输音频和视频?br />· Process 是一个记录设备(是Q一个VCR或者许多的数字讑֤Q{换模拟或者数字音频视频广播流成适合复制到磁带或其他媒体上的格式?br />· Output 是记录已格式化轨q(音频和视频)到某些类型的媒体上?br />
JMF资料处理模式
以下囄说明了JMF数据处理模块q对每个cdl出了例子:
使用此模式,很容易明白我们前面的两个例子Q从文g中输入音频和视频q输出到本地计算Z。在后面的章节中Q我们也会谈Z些通过传播和接攉频媒体的JMF|络功能?br />
处理模型例子
JMF的输入,处理和输出模式联pv来,我们能开始想象许多基于媒体的操作都可能通过JMF完成。一个例子,转换一U媒体类型ؓ其他cdq将其输出存储到一个新的文件。D一个例子,我们惌在不损坏原始文g的前提下转化一个WAV格式的音频文件ؓMP3格式。以下的q程模式插图Q就是我们将开始执行{换的步骤Q?br />本例的输入是一个WAV文g。它被一个媒体格式{换工具加工,q输出到一个新的文件。现在,让我们看看JMF API中的q个模式的每一步。我们用输入,处理和输出模式作为概念上的\标?br />
JMF输入
再JMF中,一般由一个MediaLocator对象来描qC个输入。如先前规定的,
MediaLocator的外观和行ؓ都非常象一个URLQ这样它可以唯一定|络上的一个资源。事实上Q用一个URL来创Z个MediaLocator是完全可能的Q我们在前面的两个例子中是q样做的?br />Z我们的媒体{换例子,我们需要徏立一个MediaLocator来描q最初的WAV文g。如同我们将在后面的章节中见到的Q一个MediaLocator也可以用于描qC个跨网l中媒体。在q个案例中,MediaLocator会描qC播的URL――很像一个被URL指定的在Web上的资源Q用于取代指定一个本地文件系l的文g来徏立MediaLocator?br />
一个MediaLocator和一个URL之间的不?/b>
要成功的建立一个URL对象Q需要适当的java.net.URLStreamHandler安装于系l中。这个流处理的用途是能够处理被URL描述的流cd。一个MediaLocator对象q没有这个需要。例如,我们的下个应用程序将使用实时传输协议QRTPQ在|络上传输音频。由于多数的pȝ都未为RTP协议安装一个URLStreamHandlerQ所以创Z个URL对象会失败。在q个应用中,只有MediaLocator对象会成功?br />要理解更多关于URL对象以及创徏和注册一个URLStreamHandler的信息,查阅JDK帮助文档Q查?3资源)?br />
JMF处理?/b>
当我们用JMF的时候,应用E序的处理机lg被Processor接口实例描述。你需要已有些熟悉ProcessorQ它扩展至Player接口。由于Processorl承直Player接口Q它同样也从Playerl承所有可用属性。另外,Processor增加了两个属性:Configuring和Configured。这些扩展的属性(和与之关联的ҎQ用于Processor从输入流攉信息时的通信?br />在我们的最后的例程序中Q我们将建立一个Processor用于MP3~码格式的音频{换成适合在网l上传播的格式。在E后的板块中我们会讨论创Z个简单的Processor的步骤?br />
JMF输出
有少许的Ҏ用于描述JMF中处理模式的输出状态。最单的Qƈ且我们将在最后一个例子中使用的)是javax.media.DataSink接口。一个DataSinkd媒体内容q且其传送到一些目的地。本节中最开始的音频格式转换q程中,MP3Q输出)文g被DataSink描述。在我们最后一个例子中Q我们将使用一个DataSink在实际上完成|络中传播音频媒体的工作。一个DataSink是在ManagercMQ由指定一个DataSourceQ输入到DataSinkQ和一个MediaLocatorQ输出到DataSinkQ完成的?br />一个DataSource实例描述可用于PlayersQProcessors和DataSinks的输入数据。一个处理机的输Z被描q成一个DataSource对象?br />q就是ؓ什么处理器能彼此联pv来,在同一媒体数据中完成多U操作。这也是来自Processor的输作ؓ输入被Player或者DataSink使用的原因(它可媒体传递到输出目的圎ͼ?br />一个DataSink的最后目的文件由一个MediaLocator对象说明。如同前面一PMediaLocator描述一个网l资源;q就是媒体流被传递的地方?br />
W五?传播接收媒体
JMF和实时传输协?RTP)
许多的友善网l的特征直接建立在JMF中,q些使ؓ客户端程序通过|络传输和接收媒体非常容易。当在一个网l上的一个用h要接收Q何种cȝ媒体的时候,它不需要在观看媒体前等待全部的q播下蝲到机器上Q用户可以实时的观看q播。在媒体中些提Zq个概念。通过媒体,一个网l客L能接收到其他机器上广播的音频Q甚臌取正在发生的实况视频q播?br />在IETF RFC 1889中定义了实时传输协议QRTPQ。发展在快速和可靠的状态下通过|络传输旉极其敏感的数据,RTP在JMF中用于提供给用户向其他网l节点中传输媒体的Ҏ?br />在本节中Q我们将学习我们的最后一个例E序。这里,你将学习到如何传输一个存储在一台机器上的MP3文g到另外的在同一个网l的机器上去。实际的MP3源文件ƈ不从主计机上移除,它也不复制到其他机器上去;事实上它会转换成能使用RTP传输的文件格式ƈ通过|络发送。一旦被一个客L接收刎ͼ源文Ӟ现在是RTP信息包的形式Q可以再ơ传输,q一ơ是在接收机器上可播攄一U格式?br />在MediaTransmitter.java文g中源代码查看学习以下l习?br />
讄处理模式
我们可以在前面的章节中定义的处理模式的基下来讨论我们的最l的例子。在传输机器上,处理模式看v来像q样Q?br />事实上,MediaTransmitter对象源代码包括了以下三行Q?br />
private MediaLocator mediaLocator = null;
private DataSink dataSink = null;
private Processor mediaProcessor = null;
q三个实例变量可以直接映到前面的处理模式图表,如下Q?br />· mediaProcessor变量是我们的处理器;它将负责转换音频文g从MP3文g模式C个适合通过RTP协议传输的格式?br />· dataSink变量是我们的输出块?br />· 当我们徏立DataSink时我们需要指定一个MediaLocatorQ它是DataSink的目的文件?br />
当我们通过q行DataSink我们的处理过的媒体,它将传输到我们在MediaLocator中指定的地点?br />
RTP MediaLocator
在前面的两个l习中,我们通过从文件中获得的一个URL建立了MediaLocator实例?在本l习中,我们必须建立一个MediaLocator来描q网l上媒体传播输出;换句话说Q我们必dZ个能我们的音频传播的目的地的MediaLocator。一个RTP MediaLocatorW合如下规则Q看h像一个典型的URLQ?br />
rtp://address:port/content-type
让我们看看上面URL规范的每一D:
· address 是将传输的媒体的地址。以单播的模式传输(一个专用IP地址Q,地址会是有意接收的机器的IP地址。以q播的模式传播(到子|中的所有机器)Q地址会是以255作ؓ最后的一块的子网地址。D个例子,如果我再子网中可指定地址?92.168.1和想要传播到子网中的所有节点,我可以指?92.168.1.255作ؓ地址Q这样允许子|中的每个节点监听广播媒体?br />· port 必须是被传输者和接收者都允许的一个端口?br />· content-type 是媒体流cd。在我们的案子中Q这个将会是音频?br />下面的一个简单的RTP传播MediaLocator例子会让所有在指定|络中的机器接收到媒体流Q?br />
rtp://192.168.1.255:49150/audio
创徏一个处理机
在setDataSource()Ҏ中我们首先要做的是创徏一个Processor实例?br />下面的Processor的职责是转换MP3音频媒体Z个RTP来表C:
public void setDataSource(DataSource ds) throws IOException,
NoProcessorException, CannotRealizeException, NoDataSinkException {
mediaProcessor = Manager.createRealizedProcessor(
new ProcessorModel(ds, FORMATS, CONTENT_DESCRIPTOR));
在ManagercMQ我们能创徏一个Processor对象Q通过两种Ҏ中的一U:
createProcessor()或者createRealizedProcessor()。你很可能会注意到这两个Ҏ样式的显C和前面例子中创Z个Player的方法很怼。在目前的例子中Q我们将创徏一个已实现的Processor。我们这样做是因为我们用的应用非常单,在Processo处于Realized状态时我们不需要关心Q何真实的工作?br />
创徏一个ProcessorModel
创徏一个已实现的ProcessorQ我们需要创Z个ؓProcessor描述输入和输出媒体类型的ProcessorModel实例。ؓ了创建ProcessorModelQ我们需要下面的一些:
· 一个DataSourceQ将被处理的媒体Q输入文Ӟ?br />· 一个javax.media.Format数组Q描q输入媒体的格式?br />· 一个javax.media.protocol.ContentDescriptor实例Qؓ我们的处理机描述输出格式。传送者的DataSource是通过一个参C递到此方法?br />
定义输入和输出格?/b>
因ؓ我们的MediaTransmittercM被时常用于将输入媒体格式QMP3Q{换成一U输出格式(音频RTPQ,中学对象被定义成静态。我们创Z个新的javax.media.format.AudioFormat实例用于描述媒体输入cdQ在java帮助文档中查看可用格式)。这是我们的处理机可以获取MP3音频文g的原因?br />我们也创Z个javax.media.protocol.ContentDescriptor实例来描q想要处理机输出的。在我们的案子中Q这是一个RTP媒体?br />
q就是ؓ什么我们的处理机可以只刉RTP?br />下面的代码片断显CZ我们如何讄格式和内Ҏq符变量Q用于创建ProcessorModel对象Q?br />
private static final Format[] FORMATS = new Format[] {
new AudioFormat(AudioFormat.MPEG_RTP)};
private static final ContentDescriptor CONTENT_DESCRIPTOR =
new ContentDescriptor(ContentDescriptor.RAW_RTP);
q接输入Q处理机和输?/b>
现在我们有一个处于Realized状态的ProcessorQ我们需要设|DataSink以能实际上传播RTP媒体。创建DataSink是简单的大概使用另外一个调用给Manager对象Q如下所C:
dataSink = Manager.createDataSink(mediaProcessor.getDataOutput(),
mediaLocator);
createDataSink()Ҏ获取新Processor的输出(作ؓ一个DataSource参数Q和MediaLocator对象Q我们和MediaTransmitter对象同时建立的。通过q样Q你能开始我们的不同的组件是如何在处理模式中联系h的:我们从一个Processor中获取输出ƈ使用他们作ؓ输入到其他组件。在q个Ҏ的应用中QProcessor输出用于传输媒体的DataSink的一个输入?br />
创徏一个DataSource实例
在这点上Q我们全部都是做和设|我们的媒体播放器的q播传输?br />我们需要创建DataSource对象Q我们用于创建处理机Q就是,在我们的MediaTransmitter中,参数传递到setDataSource()ҎQ。下面是创徏一个DataSource实例的代码:
File mediaFile = new File(args[1]);
DataSource source = Manager.createDataSource(new MediaLocator(
mediaFile.toURL()));
q段代码是在MediaTransmitter对象中的vmain()Ҏ。这里我们通过从命令行输入的第二个参数创徏一个File对象。我们通过文g创徏一个MediaLocatorQ而后通过位置创徏一个DataSource。这个新q创建的DataSource是一个涉及到传送者的输入文g。我们能使用q个DataSource初始化传输者?br />
开始和停止MediaTransmitter
我们通过调用其中的startTransmitting()Ҏ来开始MediaTransmitterQ如下所C:
public void startTransmitting() throws IOException {
mediaProcessor.start();
dataSink.open();
dataSink.start();
}
q个Ҏ首先开启处理机Q然后打开q启动DataSink。在q个调用后,接收机器可在媒体传送者上监听?br />停止传输者是非常单的。以下代码将DataSink和Processor都停止和关闭掉:
public void stopTransmitting() throws IOException {
dataSink.stop();
dataSink.close();
mediaProcessor.stop();
mediaProcessor.close();
}
~译和运行MediaTransmitter
通过在命令行中输入javac MediaTransmitter.java来编译例E序Q可在你的工作目录中生成一个同名的.class文g?br />要运行例E序Q在命o提示行中输入以下代码Q?br />
java MediaTransmitter rtpMediaLocator audioFile
此例创Z个myAudio.mp3文g的媒体广播。不要忘记将rtpMediaLocator替换成一个媒体传输的RTP URLQ如同先前讨论的?br />你同样也需要将audioFile替换成你本机的音频文件名?br />所有的相对文g名都是相对于当前工作目录的。你会看见一些信息标志正在播攄文g。按下Enter键来停止播放?br />
Z送者的一个例命o行交互如下:
java MediaTransmitter rtp://192.168.1.255:49150/audio myAudio.mp3
如果初始~辑p|Q确定JMF的jar文g包含CLASSPATH环境变量中。要q一步探索本E序和练习,h阅MediaTransmitter源代码?br />
接收传输的媒?/b>
现在你可能会问,“如果没有h可以看或者收听的话,q个传播媒体有什么好的??br />q运的是Q设定一个接收传播媒体的客户端只需要对我们在第二个例程序的MediaPlayerFrame源代码做很小的改动?br />MediaPlayerFramec需要一个很的调节来接收和播放音频文g。在main()Ҏ中,你需要注释掉如下的一行:
mpf.setMediaLocator(new MediaLocator(new File(args[0]).toURL()));
q且输入如下的一?
mpf.setMediaLocator(new MediaLocator(args[0]));
q个单的改动允许我们通过String来创Z个MediaLocator对象Q而不是通过创徏一个File来创建MediaLocator?br />其他代码都一栗?br />
指定RTP URL
?2늚说明~译和运行MediaPlayerFrame介绍了如何编译和q行MediaPlayerFrame例程序。这唯一的不同就是你需要ؓ传输者指定RTP URL。ؓ接收者的例命令行交互如下Q?br />
java MediaPlayerFrame rtp://192.168.1.255:49150/audio
q行|络媒体传送者的注意事项
如果你在|络上只有权使用一台机器,你仍然可以运行传输程序。当你启动传送程序的时候,你可以即使用RTP URL传输地址Q也可指定你工作的机器的机器地址。ؓ了能够调节传输,在开始前接收者必M用精的同样的RTP URL?br />如果你运行本例真实的|络版本Q每C使用的机器都需要安装JMFQ不论是传输q是接收媒体。这是必ȝQ因Z论是传送程序还是接收程序都大量的用了JMF的API?br />在Q一个案子中Q确认在指定的RTP URL中用了相同的地址和端口;否则媒体传输是不会工作的?br />
W六? U束和资?/span>
摘要
我希望本指南能给你提供如何用JMF的API的有用的览?br />我们建立了三个小的应用程序来播放本地的音频和视频Q也通过|络传播和接收媒体。这些应用程序的源代码中包含了很多的javadoc样式的注释。这有助于你理解你剩余的问题?br />许多JMF的主题在本指南中q没有涉及。实际上Q我们更xJMF的基本概念和应用Q在此基上,我们能轻易地扩展学习的其他范围。要更深入JMF的应用程序,你可能想要学习下面的面板中所提到的主题。更q一步的阅读本指南中的主题,查阅23늚资源?br />
高主题
大量的值得做的l习在本指南的范围之上。在单的说明之下自己更进一步的学习Q你可以扩展我们的应用程序代码,也可以反展你的JMF相关知识。用以下的l习开始:
· 媒体捕获QJMF包含了丰富的API来捕获媒体数据。如果你对用JMF捕获媒体感兴,你可以用javax.media.CaptureDeviceManagercdjavax.media.protocol.CaptureDevice接口的API来学习。对于一个高U的l习Q考虑使用CaptureDeviceManager和CaptureDevice接口来增加媒体捕获功能到媒体播放应用E序的GUI版本上?br />· 会话理Q由于本指南是一个JMF的说明,我们使输现非常的单,仅仅实现了javax.media.DataSink输出?br />另外的输C是使用javax.media.rtp.SessionManager。这个管理类允许客户端创建ƈ监视他们的RTP和q接。通过SessionManagerq后创建流Q它可能非常的接q监视RTP会话。作Z个高U的l习Q{换我们的C个演C程序来使用SessionManagerQ然后监听流出的RTP已l哪些客L在收听?br />· 使用JMF的多点传送:我们的广播演C应用程序说明了如何传送一个网l的媒体到另外一个网l的一或多台机器上厅R它也可能用JMF中的多点传输协议来提供给更复杂,多用L|络?br />JMF用户指南提供了一个用JMF的多播协议的更深入的探讨。更q一步追t本主题查看23资源?br />· 传输视频Q?我们的最后一个演C应用程序着g如何传输一个MP3音频文gQ但是JMF也能够通过|络传递视频。关注API文档中的Format和ContentDescriptorc获得如何用的更好的方法?br />· 导入/导出RTP媒体: JMF同样允许RTP保存ؓ文g以便来使用。D一个实例,一个远E电信会议可以保存下来以后再看?br />׃已l保存再RTP格式中,已经不需要再ơ{换,q样可导致传输程序的性能改进。通过一个文件而不是URL来设|DataSink对象中输?输出MediaLocator。你会再JMF用户指南中发现更深层ơ的主题探讨?br />
资源
JMF
· 下蝲mediaplayer.jarQ本指南中用的完整的例源代码?br />· JMF主页 (http://www.javasoft.com/jmf)是最好的探讨JMF更多信息的资源?br />· 你可以找到JMF说明?http://java.sun.com/products/java-media/jmf/2.1.1/specdownload.html)Q再Java开发者联盟上包括API文档和JMF用户指南。你必须有权使用所有的q些资源Q如果你惛_M更深入的JMF~程的话?br />· 官方的JMF支持文g格式 面
(http://java.sun.com/products/java-media/jmf/2.1.1/formats.html) 列出了所有可为JMF辨识q播攄文g格式。此文g格式面也包括了学习更多关于捕获讑֤和RTP格式的参考?br />· MPEG-4 Video for JMF (http://www.alphaworks.ibm.com/tech/mpeg-4), 来自IBM
alphaWorks, 是一个JMF的视频编解码器?br />RTP
· IETF RTP RFC (http://www.ietf.org/rfc/rfc1889.txt) 非常详细的描qCRTP协议?br />· 查看 JMF API Guide
(http://java.sun.com/products/java-media/jmf/2.1.1/specdownload.html) Q有许多有关于RTP协议和描qC及它是如何在JMF上应用的?br />· 哥u比亚大学有一个比较有用的RTP FAQ(http://www.cs.columbia.edu/~hgs/rtp/faq.html).
Java技?br />· Java 2 Platform, Standard Edition (http://java.sun.com/j2se/) 可从sun公司获得?br />· sun的指南关于JFC/Swing (http://java.sun.com/docs/books/tutorial/uiswing/index.html)
?AWT (http://java.sun.com/docs/books/tutorial/information/download.html#OLDui) 是非常好的能学习到很多关于JavaE序语言中GUI~程的好地方?br />· 另外一个sun指南学习network programming 基础
(http://java.sun.com/docs/books/tutorial/networking/index.html)?br />多点传输协议
· Explicit Multicast (XCAST)
(http://oss.software.ibm.com/developerworks/opensource/xcast/) 是IP多点传输的一UŞ式,为非常多的多点传输组设计提供可升U的支持Q这些组有些量的参与者代表。XCAST 代码得到了IBM Common Public License的认可?br />· Todd Montgomery ?MTP page (http://www.nard.net/~tmont/rm-links.html),
在这里你能找C个广泛的涉及到多点传输协议的列表?br />附加资源
· 你可以在
developerWorks Java technology zone (http://www-106.ibm.com/developerworks/java/)中找到许多的关于Java各方面的内容?br />· 查看 developerWorks tutorials page
(http://www-105.ibm.com/developerworks/education.nsf/dw/java-onlinecourse-bytitle?OpenDocument&Count=for a complete listing of free tutorials.