创业四字经 【增新版】
这个四字经涵盖了创业历程的不同方面和阶段。是许多过来人的忠告。承蒙大家喜欢原47条,另收25条。欢迎建议、补充。希望加些有本土特色的。
创业四字经
1. 慎用本钱 Watch your cash.
2. 精选同伙 Pick founders carefully.
3. 早纳全才 Hire generalists early.
4. 迟雇专家 Hire specialists later.
5. 投资文化 Invest in culture.
6. 抵挡诱惑 Avoid tempting distractions.
7. 发烧客户 Support customers maniacally.
8. 避免商计 Avoid business plans.
9. 常写博客 Write a blog.
10. 忠于数据 Never fudge numbers.
11. 百家争鸣 Encourage diverse thinking.
12. 珍惜时间 Guard your time.
13. 推迟租楼 Defer renting space.
14. 保证睡眠 Get enough sleep.
15. 延筹资金 Delay raising capital.
16. 坚忍萧条 Persist through downturns.
17. 有根有据 Decide with data.
18. 天天向上 Improve product daily.
19. 常有进账 Recognize revenue consistently.
20. 服务有偿 Start charging early.
21. 回报伯乐 Reward early adopters.
22. 常有卖点 Sell something today.
23. 不怕说不 Say “NO” often.
24. 不求完美 Accept imperfect data.
25. 热情求贤 Recruit with zest.
26. 培育良材 Nurture your best.
27. 礼待商家 Treat vendors well.
28. 充满自信 Believe in yourself.
29. 尊重对手 Respect your competitors.
30. 开怀尝新 Try something new.
31. 树立品牌 Build a brand.
32. 全神贯注 Focus, focus, focus.
33. 加速周转 Iterate more often.
34. 自创自用 Use your product.
35. 体验构想 Live your vision.
36. 举革纳谏 Encourage rational debate.
37. 迅速果断 Make decisions swiftly.
38. 直面艰险 Face harsh realities.
39. 知法守法 Don’t break laws.
40. 保重身体 Protect your health.
41. 犒劳成绩 Celebrate your successes.
42. 精简会议 Cancel unnecessary meetings.
43. 员工增值 Improve employee's resumes.
44. 小心大佬 Beware big bullies.
45. 分享经历 Share the experience.
46. 保持人缘 Maintain your relationships.
47. 开心体验 Keep it fun.
新增
48. 信任员工 Trust your Employees
49. 相信直觉 Trust your Gut
50. 带头加油 Cheerlead the Process
51. 建立自信 Believe in Yourself
52. 处处创新 Apply creativity everywhere
53. 推销理念 Sell the story
54. 重优求异 Do it different; Do it better
55. 始于足下 Take small steps
56. 适时跃进 Leap when necessary
57. 择机冒险 Punt if necessary
58. 管理风险 Minimize the risk
59. 相信账本 Listen to accountant
60. 小心快钱 Beware quick money
61. 运用媒体 Get good press
62. 预算广告 Have ad budget
63. 了解市场 Know your prospects
64. 避免积压 Don't over-produce
65. 认清同伙 Investigate your partners
66. 信任当先 Establish trust early
67. 忠实生财 Loyalty drives sales
68. 不做小人 Don't be mean
69. 回馈客户 Give something back
70. 分享成功 Help Others Succeed
71. 了解人文 Understand local culture
72. 绝不放弃 Don't Give Up
活灵活现用Git-技巧篇
上一篇介绍了Git的基本概念和一些基本命令,本篇的重点在如下三个部分:个性化定制你的Git,更酷更巧妙的使用Git,以及如何在Git Hub上开启你自己的开源项目。在所有技巧中,最重要的技巧是学会查看Git的帮助,因为Git是一个相对复杂的版本控制工具,如果你熟悉它的命令,那么给你带来的价值是不言而喻的,所以要学会掌握那根金手指─查看Git的帮助,在任何Git命令后加上'--help'就会显示该命令的帮助文档,例如 'git log --help'你就可以看到命令'git log'的所有使用方法。接下来,从打扮Git开始吧。
Git梳妆
我们可以利用Git的config命令或者直接编辑~/.gitconfig文件(如果没有的话创建它)来为自己打造独一无二的Git。我建议直接编辑用户目录下得.gitconfig文件,拿我本地的文件为例,一一为大家解说,完整的文件内容如下:
[user]
name = Phoenix
email = phoenixtoday@gmail.com
[alias]
co = checkout
ci = commit -a
st = status
br = branch
oneline = log --pretty=oneline --since='2 days ago'
onelog = log -p -1
[color]
status = auto
branch = auto
ui = auto
该文件主要包含三个部分的内容:
用户基本信息:可以设置你的名字和email,这样在你提交代码的时候就会显示出你的名字
命令别名:这是.gitconfig文件中,我最喜欢的部分,它可以大大减少你敲击键盘的次数(俗话说优秀的程序员都很懒么)。在该文件中,我将co设置为checkout的别名,那么下次我只要用'git co new_branch'就可以切换到new_branch分支下了,简洁而优雅;将ci设置为commit -a的别名,-a选项表示我不需要将修改和删除的文件通过'git add'命令来加入索引,这样设置在使用'git ci -m"message"'这样的命令时,相当于连续执行了'git add 被修改和删除的文件'和'git commit -m"message"'两条命令,再一次节省了我们宝贵的时间;最酷的是最后两行,后面的章节会一一介绍。Git提供许多优雅、人性化的选项,我们如果再结合别名的设置,可以发挥你最大的想象力,真的让你自己的Git活起来
颜色:每次看diff时是不是挺痛苦的?那么为什么不给我们的Git加上颜色呢?只需要加上那三行,就可以让红色和绿色的提示出现在你的控制台中
Git灵动
现在来讲讲'git log','git stash','git formate-patch'三个命令的用法和技巧:
git log:不同于SVN,Git将代码的历史记录全部在本地克隆了一份,所以这就使得'git log'这样的命令使用起来非常的迅速,也是我最常使用的Git命令之一。在使用'git log'的时候,你可以加入很多的后缀。'-p'表示查看修改的具体内容,例如'git log -p'它不但会打印出提交的时间、版本号、人员等,还会将具体的代码修改部分打印出来;'-n'其中n表示一个数字,这表示打印出具体的几个日志,例如 'git -p -1'正如我的Git配置文件中设置的onelog别名的内容一样,就表示打印出当前最新的一次日志记录及具体修改内容;'--since="时间/日期"','--until="时间/日期"'表示你希望查找某个日期段的日志记录,例如'git log --since="2 days ago" --until="1 hour ago"'就表示你希望查找两天前到一小时前的日志记录,Git是足够聪明的,它可以将类似于'2 days ago'和'1 hour ago'这种表示时间的英语转化为具体的时间数字;有的时候,你不希望翻很多页才可以看到所有的日志,你只希望看到简短的说明,那么Git为你提供打印格式的定制'git --pretty=格式种类',其中格式种类有full、short、oneline等,例如'git log pretty=oneline'就会将每条代码历史记录放在一行里,看起来简单明了
git stash:在第一篇中,我举了一个使用branch解决紧急任务切换的问题,其实stash命令也可以很好的解决这样的问题。当你不想提交当前完成了一半的代码,但是却不得不修改一个紧急Bug,那么使用'git stash'就可以将你当前未提交到本地(和服务器)的代码推入到Git的栈中,这时候你的工作区间和上一次提交的内容是完全一样的,所以你可以放心的修 Bug,等到修完Bug,提交到服务器上后,再使用'git stash apply'将以前一半的工作应用回来。也许有的人会说,那我可不可以多次将未提交的代码压入到栈中?答案是可以的。当你多次使用'git stash'命令后,你的栈里将充满了未提交的代码,这时候你会对将哪个版本应用回来有些困惑,'git stash list'命令可以将当前的Git栈信息打印出来,你只需要将找到对应的版本号,例如使用'git stash apply stash@{1}'就可以将你指定版本号为stash@{1}的工作取出来,当你将所有的栈都应用回来的时候,可以使用'git stash clear'来将栈清空
git format-patch:当你想给一个开源项目(例如Rails)提交一段代码的时候,或者你想给小组成员展示一段你并不想提交的代码,那么你还是需要 patch的,Git的'format-patch'命令良好的支持了这个功能。我来基本描述一下使用这个命令的步骤和方法:第一,利用branch命令创建一个分支;第二,修改你的代码;第三,在该分支上提交你的修改;第四,使用'git format-patch'命令来生成一个patch文件,例如:'git format-patch master --stdout > ~/Desktop/tmp.patch'就是将工作分支与master主干的不同,存放在'~/Desktop'文件夹下,生成一个叫做 tmp.patch的文件(另一种简单的版本是利用diff命令,例如'git diff ..master > ~/Desktop/tmp.patch'),这样就生成了patch文件。那么别人就可以使用'git apply'命令来应用patch,例如'git apply ~/Desktop/tmp.patch'就是将patch打在当前的工作分支上
Git亲友团
Git的使用技巧还包括利用Git包含的和附加的一些强大工具,这些工具主要包括git svn、git citool、gitk和Git的自动提示脚本:
git svn:Git和SVN可以很方便的集成在一起,这就大大减少了从SVN向Git迁移的学习成本,这也是我特别建议大家首次接触Git的使用方式。git svn是一个Git内置的工具,你安装了Git也就安装了它,譬如说你们团队有一个SVN服务器,但是你想利用Git本地的一些强大特性,那么你依然可以安装Git,使用Git的branch功能,只不过再更新代码和提交代码的时候,使用git svn命令即可。在这里我简单的讲讲最常使用和需要注意的两个命令,其余的命令读者可以通过'git svn --help'来查看:'git svn rebase'命令取代了'svn update'用于将服务器代码更新到本地;'git svn dcommit'取代了'svn ci',需要注意的是,本地必须用Git提交了代码之后,再使用'git svn dcommit'。只需要这样,你就可以轻松地从SVN转向Git了。
git citool:这是我个人使用率最频繁的一个工具,上一篇文章也提到了,Git可以本地提交代码,那么你自然可以本地修改你的提交了,这个工具就是可视化界面,用于修改你本地的提交。只要在你的工作区间输入'git citool',就会出现如下的界面
你可以用它来提交代码,可以用它来将你本地的修改追加在上一次提交的代码中,你还可以用它来修改你上次提交的信息等等。这个工具可以大大帮助你完成以前SVN不可能完成的任务
gitk:是一个查看主干/分支情况的工具,它主要用于观察整个项目的分支状况,使用'gitk'命令就会出现一个图形化界面供你查看,本篇就简单的说一下,大家回去试试就知道了
Git 的自动提示脚本:它是Shawn O. Pearce为了让Git使用起来更方便而写得Shell脚本,你可以在http://gitweb.hawaga.org.uk/ 找到一个叫做gitcompletion的脚本,下载下来,并按照该脚本中指导的方式进行配置,你就具有了Git自动提示(敲入部分Git命令,再按 Tab键)的功能,而且有了这个脚本,你也可以看到你当前工作在哪个branch下。惟一的不足是,它只支持Linux、Unix、Mac操作系统(推荐大家都用Mac进行开发)
Git实战─Git Hub
经过这么长时间理论知识的熏陶,想必大家早已跃跃欲试了,那么我们在Git Hub上建立一个开源项目作为实战演习吧。Git Hub是全球最大的Git服务器供应商,每个帐号有100M的免费使用空间,网址是:https://github.com/
首先我们在Git Hub上创建一个帐号,按照上面指导的方法设置好你的认证信息(每次提交代码都会需要这个认证信息)
然后,如下图新建一个项目(选择Create a New Repository),名叫git usage
在服务器端,你可以看到这个项目的信息,包括项目源代码的URL,如下图
在本地使用如下的命令,就可以完成你的第一次提交了:
mkdir git-usage(创建项目目录)
cd git-usage(进入项目目录)
git init(Git初始化)
touch README(创建一个README文件)
git add README(增加该文件到索引)
git commit -m 'first commit'(本地提交)
git remote add origin git@github.com:phoenixtoday/git-usage.git(增加远程服务器代码库地址)
git push origin master(将本地代码提交到远程服务器上)
总结
我所在的项目小组自从使用Git后,发现Git提供的种种特性大大提高了我们的开发效率,在认识Git前我们无法想象一个版本控制工具可以让开发任务切换变得如此自然流畅。所以我强烈推荐大家使用Git,你付出的学习绝对物有所值
活灵活现用Git-基础篇
Git是一个分布式的版本控制工具,本篇文章从介绍Git开始,重点在于介绍Git的基本命令和使用技巧,让你尝试使用Git的同时,体验到原来一个版本控制工具可以对开发产生如此之多的影响,文章分为两部分,第一部分介绍Git的一些常用命令,其中穿插介绍Git的基本概念和原理,第二篇重点介绍Git的使用技巧,最后会在Git Hub上创建一个开源项目开启你的Git实战之旅
Git是什么
Git在Wikipedia上的定义:它是一个免费的、分布式的版本控制工具,或是一个强调了速度快的源代码管理工具。Git最初被Linus Torvalds开发出来用于管理Linux内核的开发。每一个Git的工作目录都是一个完全独立的代码库,并拥有完整的历史记录和版本追踪能力,不依赖于网络和中心服务器。
Git的出现减轻了许多开发者和开源项目对于管理分支代码的压力,由于对分支的良好控制,更鼓励开发者对自己感兴趣的项目做出贡献。其实许多开源项目包括Linux kernel, Samba, X.org Server, Ruby on Rails,都已经过渡到使用Git作为自己的版本控制工具。对于我们这些喜欢写代码的开发者嘛,有两点最大的好处,我们可以在任何地点(在上班的地铁上)提交自己的代码和查看代码版本;我们可以开许许多多个分支来实践我们的想法,而合并这些分支的开销几乎可以忽略不计。
Git 1+1
现在进入本篇文章真正的主题,介绍一下Git的基本命令和操作,会从Git的版本库的初始化,基本操作和独有的常用命令三部分着手,让大家能够开始使用Git。
Git通常有两种方式来进行初始化:
git clone: 这是较为简单的一种初始化方式,当你已经有一个远程的Git版本库,只需要在本地克隆一份,例如'git clone git://github.com/someone/some_project.git some_project'命令就是将'git://github.com/someone/some_project.git'这个URL地址的远程版 本库完全克隆到本地some_project目录下面
git init和git remote:这种方式稍微复杂一些,当你本地创建了一个工作目录,你可以进入这个目录,使用'git init'命令进行初始化,Git以后就会对该目录下的文件进行版本控制,这时候如果你需要将它放到远程服务器上,可以在远程服务器上创建一个目录,并把 可访问的URL记录下来,此时你就可以利用'git remote add'命令来增加一个远程服务器端,例如'git remote add origin git://github.com/someone/another_project.git'这条命令就会增加URL地址为'git: //github.com/someone/another_project.git',名称为origin的远程服务器,以后提交代码的时候只需要使用 origin别名即可
现在我们有了本地和远程的版本库,让我们来试着用用Git的基本命令吧:
git pull:从其他的版本库(既可以是远程的也可以是本地的)将代码更新到本地,例如:'git pull origin master'就是将origin这个版本库的代码更新到本地的master主枝,该功能类似于SVN的update
git add:是将当前更改或者新增的文件加入到Git的索引中,加入到Git的索引中就表示记入了版本历史中,这也是提交之前所需要执行的一步,例如'git add app/model/user.rb'就会增加app/model/user.rb文件到Git的索引中
git rm:从当前的工作空间中和索引中删除文件,例如'git rm app/model/user.rb'
git commit:提交当前工作空间的修改内容,类似于SVN的commit命令,例如'git commit -m "story #3, add user model"',提交的时候必须用-m来输入一条提交信息
git push:将本地commit的代码更新到远程版本库中,例如'git push origin'就会将本地的代码更新到名为orgin的远程版本库中
git log:查看历史日志
git revert:还原一个版本的修改,必须提供一个具体的Git版本号,例如'git revert bbaf6fb5060b4875b18ff9ff637ce118256d6f20',Git的版本号都是生成的一个哈希值
上面的命令几乎都是每个版本控制工具所公有的,下面就开始尝试一下Git独有的一些命令:
git branch:对分支的增、删、查等操作,例如'git branch new_branch'会从当前的工作版本创建一个叫做new_branch的新分支,'git branch -D new_branch'就会强制删除叫做new_branch的分支,'git branch'就会列出本地所有的分支
git checkout:Git的checkout有两个作用,其一是在不同的branch之间进行切换,例如'git checkout new_branch'就会切换到new_branch的分支上去;另一个功能是还原代码的作用,例如'git checkout app/model/user.rb'就会将user.rb文件从上一个已提交的版本中更新回来,未提交的内容全部会回滚
git rebase:用下面两幅图解释会比较清楚一些,rebase命令执行后,实际上是将分支点从C移到了G,这样分支也就具有了从C到G的功能
git reset:将当前的工作目录完全回滚到指定的版本号,假设如下图,我们有A-G五次提交的版本,其中C的版本号是 bbaf6fb5060b4875b18ff9ff637ce118256d6f20,我们执行了'git reset bbaf6fb5060b4875b18ff9ff637ce118256d6f20'那么结果就只剩下了A-C三个提交的版本
git stash:将当前未提交的工作存入Git工作栈中,时机成熟的时候再应用回来,这里暂时提一下这个命令的用法,后面在技巧篇会重点讲解
git config:利用这个命令可以新增、更改Git的各种设置,例如'git config branch.master.remote origin'就将master的远程版本库设置为别名叫做origin版本库,后面在技巧篇会利用这个命令个性化设置你的Git,为你打造独一无二的 Git
git tag:可以将某个具体的版本打上一个标签,这样你就不需要记忆复杂的版本号哈希值了,例如你可以使用'git tag revert_version bbaf6fb5060b4875b18ff9ff637ce118256d6f20'来标记这个被你还原的版本,那么以后你想查看该版本时,就可以使用 revert_version标签名,而不是哈希值了
Git之所以能够提供方便的本地分支等特性,是与它的文件存储机制有关的。Git存储版本控制信息时使用它自己定义的一套文件系统存储机制,在代码根目录下有一个.git文件夹,会有如下这样的目录结构:
点击查看原始尺寸
有几个比较重要的文件和目录需要解释一下:HEAD文件存放根节点的信息,其实目录结构就表示一个树型结构,Git采用这种树形结构来存储版本信息,那么HEAD就表示根;refs目录存储了你在当前版本控制目录下的各种不同引用(引用指的是你本地和远程所用到的各个树分支的信息),它有heads、remotes、stash、tags四个子目录,分别存储对不同的根、远程版本库、Git栈和标签的四种引用,你可以通过命令'git show-ref'更清晰地查看引用信息;logs目录根据不同的引用存储了日志信息。因此,Git只需要代码根目录下的这一个.git目录就可以记录完整的版本控制信息,而不是像SVN那样根目录和子目录下都有.svn目录。那么下面就来看一下Git与SVN的区别吧
Git与SVN的不同
SVN(Subversion)是当前使用最多的版本控制工具。与它相比较,Git最大的优势在于两点:易于本地增加分支和分布式的特性。
下面两幅图可以形象的展示Git与SVN的不同之处
对于易于本地增加分支,图中Git本地和服务器端结构都很灵活,所有版本都存储在一个目录中,你只需要进行分支的切换即可达到在某个分支工作的效果。而SVN则完全不同,如果你需要在本地试验一些自己的代码,只能本地维护多个不同的拷贝,每个拷贝对应一个SVN服务器地址。举一个实际的例子,以前我所在的小组使用SVN作为版本控制工具,当我正在试图增强一个模块,工作做到一半,由于会改变原模块的行为导致代码服务器上许多测试的失败,所以并没有提交代码。这时候上级对我说,现在有一个很紧急的Bug需要处理, 必须在两个小时内完成。我只好将本地的所有修改diff,并输出成为一个patch文件,然后回滚有关当前任务的所有代码,再开始修改Bug的任务,等到修改好后,在将patch应用回来。前前后后要完成多个繁琐的步骤,这还不计中间代码发生冲突所要进行的工作量。可是如果使用Git, 我们只需要开一个分支或者转回到主分支上,就可以随时开始Bug修改的任务,完成之后,只要切换到原来的分支就可以优雅的继续以前的任务。只要你愿意,每一个新的任务都可以开一个分支,完成后,再将它合并到主分支上,轻松而优雅。
分布式对于Git而言,你可以本地提交代码,所以在上面的图中,Git有利于将一个大任务分解,进行本地的多次提交,而SVN只能在本地进行大量的一次性更改,导致将来合并到主干上造成巨大的风险。Git的代码日志是在本地的,可以随时查看。SVN的日志在服务器上的,每次查看日志需要先从服务器上下载下来。我工作的小组,代码服务器在美国,每次查看小组几年前所做的工作时,日志下载就需要十分钟,这不能不说是一个痛苦。后来我们迁移到Git上,利用Git日志在本地的特性,我用Ruby编写了一个Rake脚本,可以查看某个具体任务的所有代码历史,每次只需要几秒钟,大大方便我的工作。当然分布式并不是说用了Git就不需要一个代码中心服务器,如果你工作在一个团队里,还是需要一个服务器来保存所有的代码的。
总结
本篇介绍了Git的基本概念、一些常用命令和原理,大家可以尝试动手体会一下,下一篇会重点介绍Git命令的使用技巧,Git附带的工具,最后会在Git Hub上创建一个开源项目,敬请期待。
2010年中国互联网最火爆六大领域
2009年,中国网民规模达到了3.84亿人,普及率达到28.9%。而四川网民达到了1635万,增速居全国第五。据艾瑞咨询统计,2009年中国互联网经济规模达743亿元,预测2010年互联网经济年营收规模将超1000亿元。
2010年,中国互联网领域会有哪些新兴的商业模式概念突进,成为这个产业里的火爆者?昨天,记者采访了国内著名IT评论人、互联网实验室原总裁刘兴亮。在他看来,微博客、云计算、网络游戏、电子商务、企业级互联网解决方案、HULU式视频网站,可能是2010年中国互联网最火爆的六大领域。
领域1:微博客 将成为各大网站的必备
记者:微博客实际上去年就看出红火的苗头,今年是不是会扩展到更多网站来应用?
刘兴亮:微博客可以算是新兴起的一类开放互联网社交服务,国际上最知名的微博网站是Twitter,目前已是最炙手可热的互联网新贵,美国总统奥巴马、美国白宫、FBI、Google、HTC、DELL、福布斯、通用汽车等都在Twitter上进行营销和与用户交互。而在国内,目前著名的微博有:新浪微博、搜狐微博、网易微博、嘀咕、叽歪、滴、做啥、139说客、9911等。
年终岁末,微博这种新式互联网应用在中国异常火爆。毫无疑问,微博将是互联网行业未来两三年引导创新的热点,也将是潮流引爆点。可以预测的是,就像BBS、博客一样,2010年微博客也将成为各大网站不可或缺的一部分。到了2010年年底,如果没有配备微博客,都不好意思说自己是中大型网站。
领域2:云计算 今年可获得两倍增长
记者:对云计算的增长前景,你给一个通俗的说法吧?
刘兴亮:狭义云计算是指IT基础设施的交付和使用模式,指通过网络以按需、易扩展的方式获得所需的资源;广义云计算是指服务的交付和使用模式,指通过网络以按需、易扩展的方式获得所需的服务。这种服务可以是IT和软件、互联网相关的,也可以是任意其他的服务。通俗点说,云计算就好像电表和电线路,用户不需要自己再发电了,只需要接上电,安上电表,按需付费即可;也可以比喻为煤气管道,用户再也不需要自己去买一罐一罐的煤气了。
现在我们开一个公司,首先要考虑是买很多电脑,配备几台服务器。再过几年,回过头来看看今天开公司的做法,可能就会感觉很傻。就好像早些年,开公司开工厂必须先买发电机一样。但现在,谁还买发电机?云计算就是这么个玩意。提供云计算服务的公司,在2010年至少可以获得两倍的增长。
领域3:手机游戏将逐渐向网游全面过渡
记者:网络游戏已经是一个老生常谈
的领域,今年会有什么新的变化?
刘兴亮:即使最不乐观地估计,2010年网络游戏也将增长30%左右。其中,手机游戏力量进一步崛起,应用商店模式将改变手机游戏研发企业(CP)对SP渠道的严重依赖,手机游戏研发企业将成为电信运营商、通讯设备制造商、移动应用增值服务商(SP)及各种投资机构争相拉拢的对象。同时,手机游戏业将与当年PC游戏一样进一步向网游全面过渡。
领域4:电子商务 B2C将取代C2C成为主流
记者:电子商务今年的突破点在哪里?刘兴亮:电子商务经历了过去近十年的高速发展之后,正在逐步进入一个新的发展时期。这些年,中国电子商务的主流是C2C,这有点不正常。进入2010年之后,B2C模式将逐渐成为主流。除了京东、VANCL这些平台外,2010年更多的传统企业会纷纷“触网”,加入B2C行列。电子商务将引领整个互联网产业的发展。目前互联网行业迎来了第三股浪潮,将把互联网植入传统产业。当两者无缝对接后,会产生全新的商业模式,对企业的组织结构、经营模式都将带来巨大冲击。
领域5:企业级解决方案 舆情监测将越来越受企业重视
记者:你看好的企业级互联网解决方案,是不是指第三方提供的建站类服务?
刘兴亮:不光是这样。你可以看到,当越来越多的传统企业加入互联网大潮后,就迫切需要有专门的公司为他们量身定做一整套的互联网解决方案,可能会包括网站建设、SEO、舆情监测、电子商务等等。同时,互联网行业将越来越细分化,比如舆情监测等,即使互联网公司也需要,也越来越重视。
领域6:视频网站 以版权内容为主的网站大行其道
记者:视频网站去年以版权纠纷最为抢眼,是不是会由此导致今年市场格局的变化呢?
刘兴亮:目前看来,视频网站主要有两个派别,一个是以版权内容为主的主流资讯网站,代表选手是由NBC和新闻集团共同注册成立的Hulu;另一个派别就是以YouTube为代表的视频分享网站,强调原创性和自由分享。
前几年的中国网络视频市场上,视频分享网站发展得异常迅猛。但到了去年末,发展势头悄然出现了变化。随着网络视频国家队的进入,百度、网易等准备开始做以版权内容为主的视频网站,再加上搜狐、酷6等大规模删除了非版权内容,视频分享网站已经不再主流,开始走向衰落。
从受广告主青睐的程度来看,视频分享网站没法和主流视频资讯网站相比。美国市场就是一个典型的例子,后起步的Hulu已经盈利,先发展的YouTube却还在苦苦挣扎。我预测,2010年,HULU式视频网站将大行其道。(罗曙驰)
工作累了看看:美国联邦法律规定
1)不得与豪猪发生性关系。(靠,谁敢呀)
2)每周四晚6:00以后不得放P。(以后还真要小心了,别一不留神坐牢了还不知为啥)
3)任何人不得销售其子女。(好象中国也不许吧)
无论任何时候,将冰激淋卷放在口袋里是违法的。(有病丫的)
阿肯色州:
男性可以合法殴打其配偶,但每月最多一次。(估计很多东北的兄弟知道了一定想移民阿肯色了,可也有例外呀,克林顿就是阿肯色的前州长,咋老被喜莱莉扁呀)
亚利桑纳州:
任何房间中不得有两根以上的假阳具。(估计那州的最高法官丫是个变态狂!)
夏威夷州:
不得将谷物放在耳朵里。(神经病,以为偷太空种子呀)
肯塔基州:
1)任何年满18岁的男性,若与17岁以下的女性发生性关系,而且当时她又没穿鞋袜,那将课重罪。(兄弟们千万注意了呀!别全脱了)
2)圆周率在该州法定为4。(活活气死咱祖聪之前辈呀!)
爱荷华州:
1)男人如果给他的情人送一盒巧克力糖的话,那么这盒糖的重量绝不能低于50磅,否则情人有权上告
3)任何有胃病的男性不得在公共场所与女性接吻。(接吻和胃有关系吗?男性胃癌晚期患者的福音)
1)不得仅为娱乐而将球砸向他人脑袋。(谋杀可以不?真的脑子进水了)
2)10:00以后不得穿拖鞋。(光脚吧)
凡谋杀时不得穿防弹背心。(管得着吗,警察这么没自信!)
北卡州:
任何一位未婚男性与一为未婚女性,如果在任何旅馆或汽车旅馆登记为已婚,那么他们即算合法夫妻了。(想带小蜜开房的兄弟们千万别去那州呀!)
宾西法尼亚州:
不得在浴室唱歌。(难怪在宾大商学院的同胞都不会K歌)
加利福尼亚州:
仅在每周六,男性被允许在法院的门前台阶上合法殴打其配偶。(这是啥规定,郁闷ING)
犹他州:
1)不喝牛奶违法。(喝不完援助非洲难民呀,干么为难自己!难怪俺一只要喝牛奶就拉肚子的朋友从犹他转到纽约了,保命要紧呀。)
2)不得在正在执行急救任务的救护车后座上做爱。(这好理解,怕病人看见血管 爆裂么!哈哈)
让JAVA活起来—-很欣赏(JMF媒体框架)
Java媒体框架(JMF)使你能够编写出功能强大的多媒体程序,却不用关心底层复杂的实现细节。JMF API的使用相对比较简单,但是能够满足几乎所有多媒体编程的需求。在这篇文章中,我将向你介绍如何用很少的代码就编写出多媒体程序。
Java多媒体框架(JMF)中包含了许多用于处理多媒体的API。它是一个相当复杂的系统,完全了解这个系统可能需要花上几周的时间,但是这篇文章将主要介绍JMF的几个核心接口和类,然后通过一个简单的例子向你展示如何利用该接口进行编程。
JMF目前的最新版本是2.1,Sun通过它向Java中引入处理多媒体的能力。下面是JMF所支持的功能的一个概述:
● 可以在Java Applet和应用程序中播放各种媒体文件,例如AU、AVI、MIDI、MPEG、QuickTime和WAV等文件。
● 可以播放从互联网上下载的媒体流。
● 可以利用麦克风和摄像机一类的设备截取音频和视频,并保存成多媒体文件。
● 处理多媒体文件,转换文件格式。
● 向互联网上传音频和视频数据流。
● 在互联网上广播音频和视频数据。
JMF的结构
为了更好地说明JMF的结构,让我们用立体声音响做一个简单的比喻。当你CD机播放CD唱片的时候,CD唱片向系统提供音乐信号。这些数据是在录音棚中用麦克风和其他类似的设备记录下来的。CD播放机将音乐信号传送到系统的音箱上。在这个例子中,麦克风就是一个音频截取设备,CD唱片是数据源,而音箱是输出设备。
JMF的结构和立体声音响系统非常相似,在后面的文章中,你会遇到下面的这些术语:
● 数据源(Data source)
● 截取设备(Capture Device,包括视频和音频截取设备)
● 播放器(Player)
● 处理器(Processor)
● 数据格式(Format)
● 管理器(Manager)
下面让我们来看一看这些术语到底代表什么意思。
1.数据源
就像CD中保存了歌曲一样,数据源中包含了媒体数据流。在JMF中,DataSource对象就是数据源,它可以是一个多媒体文件,也可以是从互联网上下载的数据流。对于DataSource对象,一旦你确定了它的位置和类型,对象中就包含了多媒体的位置信息和能够播放该多媒体的软件信息。当创建了DataSource对象后,可以将它送入Player对象中,而Player对象不需要关心DataSource中的多媒体是如何获得的,以及格式是什么。
在某些情况下,你需要将多个数据源合并成一个数据源。例如当你在制作一段录像时,你需要将音频数据源和视频数据源合并在一起。JMF支持数据源合并,在后面的例子中我们将提到这一点。
2.截取设备
截取设备指的是可以截取到音频或视频数据的硬件,如麦克风、摄像机等。截取到的数据可以被送入Player对象中进行处理。
3.播放器
在JMF中对应播放器的接口是Player。Player对象将音频/视频数据流作为输入,然后将数据流输出到音箱或屏幕上,就像CD播放机读取CD唱片中的歌曲,然后将信号送到音箱上一样。Player对象有多种状态,JMF中定义了JMF的六种状态,在正常情况下Player对象需要经历每个状态,然后才能播放多媒体。下面是对这些状态的说明。
● Unrealized:在这种状态下,Player对象已经被实例化,但是并不知道它需要播放的多媒体的任何信息。
● Realizing:当调用realize()方法时,Player对象的状态从Unrealized转变为Realizing。在这种状态下,Player对象正在确定它需要占用哪些资源。
● Realized:在这种状态下Player对象已经确定了它需要哪些资源,并且也知道需要播放的多媒体的类型。
● Prefetching:当调用prefectch()方法时,Player对象的状态从Realized变为Prefetching。在该状态下的Player对象正在为播放多媒体做一些准备工作,其中包括加载多媒体数据,获得需要独占的资源等。这个过程被称为预取(Prefetch)。
● Prefetched:当Player对象完成了预取操作后就到达了该状态。
● Started:当调用start()方法后,Player对象就进入了该状态并播放多媒体。
4.处理器
处理器对应的接口是Processor,它一种播放器。在JMF API中,Processor接口继承了Player接口。 Processor对象除了支持支持Player对象支持的所有功能,还可以控制对于输入的多媒体数据流进行何种处理以及通过数据源向其他的Player对象或Processor对象输出数据。
除了在播放器中提到了六种状态外,Processor 对象还包括两种新的状态,这两种状态是在Unrealized状态之后,但是在Realizing状态之前。
● Configuring:当调用configure()方法后,Processor对象进入该状态。在该状态下,Processor对象连接到数据源并获取输入数据的格式信息。
● Configured:当完成数据源连接,获得输入数据格式的信息后,Processor对象就处于Configured状态。
5.数据格式
Format对象中保存了多媒体的格式信息。该对象中本身没有记录多媒体编码的相关信息,但是它保存了编码的名称。Format的子类包括AudioFormat和VideoFormat类,ViedeoFomat又有六个子类:H261Format、H263Format、IndexedColorFormat、JPEGFormat、RGBFormat和YUVFormat类。
6.管理器
JMF提供了下面四种管理器:
● Manager:Manager相当于两个类之间的接口。例如当你需要播放一个DataSource对象,你可以通过使用Manager对象创建一个Player对象来播放它。使用Manager对象可以创建Player、Processor、DataSource和DataSink对象。
● PackageManager:该管理器中保存了JMF类注册信息。
● CaptureDeviceManager:该管理器中保存了截取设备的注册信息。
● PlugInManager:该管理器中保存了JMF插件的注册信息。 创建一个Player对象
在JMF编程中,最常见的工作就是创建一个Player对象。你可以通过Manager类的createPlayer()方法创建Player对象。Manager对象使用多媒体的URL或MediaLocator对象来创建Player对象。当你获得了一个Player对象后,你可以通过调用getVisualComponent()方法得到Player对象的图像部件(Visual Component,在图像部件上可以播放多媒体的图像)。然后将图像部件加入到应用程序或Applet的界面上。Player对象还包含一个控制面板,在上面可以控制媒体的播放、停止和暂停等。
Player类中的很多方法只有在Player对象处于Realized的状态下才会被调用。为了保证Player对象已经到达了该状态,你需要使用Manager的createRealizePlayer()方法来获得Player对象。但是对于start()方法来说,你可以在Player对象到达Prefetched状态之前调用它,它可以自动将Player的状态转换到Started状态。
截取多媒体数据
多媒体数据的截取是JMF程序中另一个非常重要的功能。你可以按照下面的步骤截取数据:
● 通过查询CaptureDevieceManager获得你希望使用的截取设备。
● 获得设备对应的CaptureDeviceInfo对象。
● 从CaptureDeviecInfo对象中获得MediaLocator对象,然后用它创建一个DataSource对象。
● 使用DataSource对象创建Player对象或Processor对象。
● 调用start()方法,开始截取多媒体数据。
你可以使用CaptureDeviceManager对象获得系统中可用的视频和音频截取设备。通过调用getDeviceList()方法你可以获得设备的列表。每个设备都对应一个CaptrueDeviceInfo对象。也可以通过调用CaptureDevieceManager对象的getDevice()方法来获得特定的CaptureDeviceInfo对象。在使用设备截取多媒体数据前,还需要从CaptureDeviceInfo对象中获得设备对应的MediaLocator对象。然后你可以直接使用MediaLocator来构造Player或Processor的实例,也可以用MediaLocator构造一个DataSource对象,然后将DataSource对象送入Player或Processor对象中。最后调用start()方法来截取多媒体数据。
一个JMF例子
当你使用JMF进行编程以前,你需要安装JMF。同时在硬件上也有一些要求。由于本文的代码是在Windows 2000下编写和测试,因此文章中提到的操作系统需要的软件都是与Windows有关的。虽然Java是跨平台的,但是JMF是个例外――并不是所有的平台上都实现了JMF。
硬件和软件要求
硬件方面你需要与SoundBlaster兼容的声卡,芯片最好使用奔腾III以上的芯片。内存最好不小于64MB。同时你需要安装下面的软件:
● Windows95/98,Windows NT 4.0, Windows2000或 WindowsXP。
● JDK1.1.6或以上的Windows版本。
● JMF类和动态库
在Windows下安装JMF2.1
当下载了JMF2.1以后,运行jmf-2_1_1b-windows-i586.exe。该程序会将JMF2.1安装到你指定的目录下。当安装成功后,你需要确认一下安装程序正确设定了CLASSPATH和PATH环境变量。在CLASSPATH中需要包含jmf.jar和sound.jar;在PATH中需要包含JMF动态库的路径。
JMFRegistry
如果你希望使用视频和音频截取的设备,你需要确认安装了这些设备的驱动程序。除此之外,你还需要运行JMFRegistry应用程序。JMFRegistry可以向JMF注册新的数据源、媒体处理器、插件、视频和音频截取设备,然后你才能够在你的程序中使用它们。你只需要运行一次JMFRegistry就能注册系统中所有的视频和音频截取设备。
当你运行了JMFRegistry后,会弹出图一所示的窗口:
图一 通过JMFRegistry注册视频和音频截取设备
选择“Capture Devices”标签,然后按下“Detect Capture Devices”按钮,程序将自动检测出系统中的视频和音频截取设备。在左边的类表框中会列出所有检测到的设备的名称。在图一中我们看到JMFRegsitery发现了JavaSound audio capture、vfw:Logitech USB Video Camera:0和vfw:Microsoft WDM Image Capture (Win32):1。单击某个设备可以看到该设备支持的视频或音频格式。如果JMFRegistry无法检测到设备,有可能是没有正常安装设备的驱动程序。
例子程序
由于JMF2.1比较复杂,我不可能在在例子中包含JMF2.1支持的所有功能。因此我选择了下面几个在JMF中比较常用的功能:播放多媒体、注册音频和视频截取设备、截取视频和音频。
1.播放多媒体
在JMF.java中有一个play()方法。该方法可以播放用户选择的多媒体文件。当播放多媒体文件时,你需要一个Player对象。在例子中,dualPlayer就是Player接口的实现对象。
Player dualPlayer;
在Play()方法中,通过使用FileDialog获得媒体文件的路径和文件名,并保存在filename中。
try {
FileDialog fd =
new FileDialog(this, "Select File", FileDialog.LOAD);
fd.show();
String filename = fd.getDirectory() + fd.getFile();
...
}
catch (Exception e) {
System.out.println(e.toString());
}
然后你需要通过媒体管理器Manager间接创建一个Player对象。你可以使用Manager类的createPlayer()方法或者createProcessor()方法来获得一个Player对象或Processor对象。在play()方法中,我使用的是createPlayer()方法。
dualPlayer = Manager.createPlayer
(new MediaLocator("file:///" + filename));
有时你需要使用一个Player对象来控制多个其他的Player和Controller对象,我们把这个Player对象称为主对象,并把这些对象组成一个组。通过调用主对象中的start()、stop()、setMediaTime()等方法就可以激活组中所有成员的相应方法。主对象控制所有的状态变化和事件发布。然后使用addControllerListerner()方法来将一个ControllerListener对象绑定到Player对象上,Controller对象将向该ControllerListener对象发送事件消息。
dualPlayer.addControllerListener(this);
最后需要调用start()方法来启动Player对象。start()方法将Player对象的状态设置为Started。如果Player没有被实体化(Realize)或预取(Prefetch),start()方法会自动执行这些操作。
dualPlayer.start();
由于JMF类实现了ControllerLister接口,因此需要实现该接口中的controllerUpdate()方法,该方法在Controller对象产生一个事件时被调用。
public synchronized void controllerUpdate(ControllerEvent event) {
if (event instanceof RealizeCompleteEvent) {
Component comp;
if ((comp = dualPlayer.getVisualComponent()) != null)
add ("Center", comp);
if ((comp = dualPlayer.getControlPanelComponent()) != null)
add("South", comp);
validate();
}
}
当JMF类产生了一个RealizeCompleteEvent事件后,controllerUpdate()方法在界面上增加两个Component对象,一个用于播放媒体,一个用于放置控制按钮,例如播放、停止等。
在运行程序的过程中,程序会产生下面的输出。
Starting player ...javax.media.TransitionEvent
[source=com.sun.media.content.video.mpeg.Handler@71bb78,
previous=Unrealized,
current=Realizing,
target=Started]
Open log file: C:/test/Java/JMF/JMF/jmf.log
javax.media.DurationUpdateEvent
[source=com.sun.media.content.video.mpeg.Handler@71bb78,duration=
javax.media.Time@2a37a6
javax.media.RealizeCompleteEvent
[source=com.sun.media.content.video.mpeg.Handler@71bb78,
previous=Realizing,
current=Realized,
target=Started]
Adding visual component
Adding control panel
javax.media.TransitionEvent
[source=com.sun.media.content.video.mpeg.Handler@71bb78,
previous=Realized,
current=Prefetching,
target=Started]
javax.media.PrefetchCompleteEvent
[source=com.sun.media.content.video.mpeg.Handler@71bb78,
previous=Prefetching,
current=Prefetched,target=Started]
javax.media.StartEvent
[source=com.sun.media.content.video.mpeg.Handler@71bb78,
previous=Prefetched,
current=Started,
target=Started,
mediaTime=javax.media.Time@56a05e,timeBaseTime=
javax.media.Time@3a8602]
javax.media.EndOfMediaEvent
[source=com.sun.media.content.video.mpeg.Handler@71bb78,
previous=Started,
current=Prefetched,
target=Prefetched,
mediaTime=javax.media.Time@1d332b]
前面提到,当调用start()方法的时候,Player会切换到Started状态。从上面列出的信息中可以看到Player对象的状态从Unrealized变成了Started。当EndOfMedia事件被激活时(这时Player对象完成了媒体文件的播放),状态从Started变成了Prefetched。图二显示了程序正在播放多媒体文件时的情况。
图二 程序正在播放媒体文件
2.注册音频和视频截取设备
在例子中,注册音频和视频截取设备的方法只在程序的内部注册这些设备,在程序外则不起作用。该方法的作用是当用户的计算机上存在多和音频和视频截取设备时,告诉程序因该使用哪个设备和这些设备支持的音频和视频格式。因此在进行截取处理之前需要获得设备的配置信息。在例子中,当在Configure菜单上按下Capture Device命令后,会弹出CaptureDeviceDialog对话框。如果在截取音频或视频前没有设定设备的配置,也会弹出该对话框。图三显示了该对话框。
图三 设备注册对话框
让我们来看一下CaptureDeviceDialog类中的init()方法:在初始化了界面之后,通过调用CaptureDeviceManager类的getDeviceList()方法:
devices = CaptureDeviceManager.getDeviceList ( null );
CaptureDeviceManager类使用查询机制和一个注册表来定位设备,然后将设备的信息放入CaptureDeviceInfo对象中返回。我们还可以利用CaptureDeviceManager类来注册新的设备。通过调用getDeviceList()方法程序获取了一个支持指定格式的设备的列表。在例子中,我将格式参数设定为null,这意味着设备可以使用任何格式。返回值被放入device变量中。如果getDeviceList()方法返回的是一个非空值,程序会将包含在其中的音频设备名称和视频设备名称分别放入两个下拉列表中中,但是到目前为止我们还不知道哪些设备是音频设备,哪些是视频设备。
我们可以通过CaptureDeviceInfo的getFormat()方法获得Format对象组数,在Format对象中保存了设备支持的媒体格式。Format类间接被AudioFormat和VideoFormat类所继承。因此我们可以利用设备支持的格式类型来区分设备的类型:
if (devices!=null && devices.size()>0) {
int deviceCount = devices.size();
audioDevices = new Vector();
videoDevices = new Vector();
Format[] formats;
for ( int i = 0; i < deviceCount; i++ ) {
cdi = (CaptureDeviceInfo) devices.elementAt ( i );
formats = cdi.getFormats();
for ( int j=0; j<formats.length; j++ ) {
if ( formats[j] instanceof AudioFormat ) {
audioDevices.addElement(cdi);
break;
}
else if (formats[j] instanceof VideoFormat ) {
videoDevices.addElement(cdi);
break;
}
}
}
. . .
}
上面的程序运行后,audioDevices()中将包含所有的音频设备,videoDevices()中将保存所有的视频设备。其中cdi是CaptureDeviceInfo对象。然后将设备名称填入下拉列表中:
// 将音频设备显示在下拉列表中
for (int i=0; i<audioDevices.size(); i++) {
cdi = (CaptureDeviceInfo) audioDevices.elementAt(i);
audioDeviceCombo.addItem(cdi.getName());
}
// 将视频设备显示在下拉列表中
for (int i=0; i<videoDevices.size(); i++) {
cdi = (CaptureDeviceInfo) videoDevices.elementAt(i);
videoDeviceCombo.addItem(cdi.getName());
}
然后程序显示出当前选中的设备支持的格式:
displayAudioFormats();
displayVideoFormats();
下一步需要获取用户选中的音频设备和视频设备以及它们支持的格式,相关的方法是JMF类中的getAudioDevice()、getVideoDevice()、getAudioFormat()和getVideoFormat()方法。然后将获取的对象分别保存到audioCDI,videoCDI,audioFormat和videoFormat中:
audioCDI = cdDialog.getAudioDevice();
if (audioCDI!=null) {
audioDeviceName = audioCDI.getName();
System.out.println("Audio Device Name: " + audioDeviceName);
}
videoCDI = cdDialog.getVideoDevice();
if (videoCDI!=null) {
videoDeviceName = videoCDI.getName();
System.out.println("Video Device Name: " + videoDeviceName);
}
// 获得选中的多媒体格式
videoFormat = cdDialog.getVideoFormat();
audioFormat = cdDialog.getAudioFormat();
3.截取视频和音频
使用capture()方法可以截取音频和视频数据。但是在使用该方法前需要确定是否已经选中了视频和音频截取设备:
if (audioCDI==null && videoCDI==null)
registerDevices();
和play()方法类似,可以通过使用Manger类中的静态方法createPlayer()创建一个Player对象,该对象可以播放一个DataSource对象中的数据流。
Player createPlayer(MediaLocator sourceLocator)
在例子中,我首先通过调用audioCDI和videoCDI的getLocator()方法来获得MediaLocator对象,然后利用Manager类的createPlayer()方法创建Player对象。最后将一个ControllerListener对象绑定到视频Player对象上并开始播放。
videoPlayer = Manager.createPlayer(videoCDI.getLocator());
audioPlayer = Manager.createPlayer(audioCDI.getLocator());
videoPlayer.addControllerListener(this);
videoPlayer.start();
audioPlayer.start();
使用这种方法导致最后获得了两个Player对象。我们也可以使用Manager类中的createDataSource()方法从视频和音频CaptureDeviceInfo对象(audioCID和videoCDI)中获得视频和音频数据源(DataSource对象),然后调用createMergingDataSource()方法将两个数据源合并成一个数据源(ds):
DataSource[] dataSources = new DataSource[2];
dataSources[0] =
Manager.createDataSource(audioCDI.getLocator());
dataSources[1] =
Manager.createDataSource(videoCDI.getLocator());
DataSource ds = Manager.createMergingDataSource(dataSources);
然后可以使用ds作为createPlayer()方法的参数来获得一个Player对象dualPlayer。调用addControllerListener()就可以进行播放了。
dualPlayer = Manager.createPlayer(ds);
dualPlayer.addControllerListener(this);
dualPlayer.start();
小结
Java多媒体框架是一个很好的多媒体编程工具。在这篇文章中我只是简单介绍了JMF的一些基本功能。如果有兴趣的话可以仔细阅读一下Sun公司的Java网站上提供的JMStudio的例子。在JMStudio中不仅实现了简单的播放和视频/音频截取功能,还实现了从互联网下载和向互联网上传多媒体数据流的功能。而且它还包含了JMFRegistry的源代码,将相应的代码移植到你的应用程序中后,你就不需要在运行程序前运行JMFRegistry来向JMF注册设备了。
作者简介:冯睿,2000年毕业于美国Northern Illinois大学电气工程系,获硕士学位。随后在New Monics软件公司工作了一年,其间参加了Java虚拟机的开发和优化工作。目前在国内一家GIS公司担任项目经理,主要从事应急指挥系统的交通GIS系统的开发
java 媒体框架基础(JMF)
Java媒体架构基础
内容表格
1. 关于此指南
2. 一个简单的音频播放器
3. JMF用户接口组件
4. JMF概念
5. 传播和接收媒体
6. 总结以及资源
第一节. 关于此指南
此指南包含的内容?
Java媒体架构(JMF)是一个令人激动的通用的API,它允许Java开发者用许多不同的方法处理媒体。本指南主要通过使用工作的例子提供一个JMF的一些主要的特征的概述。阅读完本指南后,你将会明白JMF体系结构中的主要播放功能。你同样能正确的使用JMF,使用现存的例子和可为更多特殊功能扩展的源代码。
本指南包含着以下主题:
· 下载和安装JMF
· 主要的JMF类以及它们在JMF体系结构中的应用
· 播放本地的媒体文件
· 为媒体的存取和操作制作以和图形用户界面(GUI)
· 通过网络传播媒体
· 通过网络接收媒体
几乎所有的媒体类型的操作和处理都可以通过JMF来实现。全面的讨论JMF所提供的所有特征已经超过了本指南的范围,我们将使用三个简单的媒体应用程序来学习此框架的构建模块。通过这个方法,本指南将为你未来学习和实施更多特殊的应用提供准备。
我应该使用此指南吗?
本指南会带你学习使用JMF工作的基础。为完成这些,我们会创建三个的独立工作的例程序。每个例子都会建立前一个例子的基础上,显示JMF功能性的不同方面。
在本指南中的例子假定你曾经使用过并且已经熟悉了Java程序语言。除了Java核心和JMF的类之外,我们会使用一些Java AWT和Swing类(用于创建GUI),也会有一些Java网络类(用于在网络中传输媒体)。对GUI和网络类一些熟悉有助于你更快的明白观点和这里的例子,但并非是阅读本指南必须的。
我们将学习的例程序如下
· 一个简单的音频播放器(JMF的HelloWorld应用):这个字符界面的播放器通过在命令行中简单的输入媒体文件的名字就可以播放大多数的音频类型。此音频播放器的演示大体上显示了JMF的特有的类。
· 一个图形界面的媒体播放器:我们将使用JMF内置的接口组件来建立图形界面,所以在此练习中必须有一些图形界面的编程经验。这个媒体阅览器演示使用了一些Java AWT和Swing类来为用户显示图形组件。
· 一个媒体广播应用:此应用程序允许一个本地媒体文件通过网络传播。此程序能灵活的使媒体只传输到指定的网络节点,或者传输到一个子网络中的所有节点。此演示使用了一些Java的网络APIs来在网络中传输媒体。
作为第三个练习的一部分,我们将修改图形界面的播放器,让其能接收并且播放媒体。
跳至23页观看Resources,文章,指南,和其他参考书目的列表,这会帮助你学习到更到关于此指南包括的主题。
安装需求
要运行此指南中的例程序,你需要如下的工具和组件:
· Java 2 平台,标准版,编译和运行演示程序
· Java媒体框架,版本2.1.1a或者更高
· 一块已经安装并且配置号的适当的声卡
· 一台或者多台测试机器
· 演示的源代码文件在mediaplayer.jar中
最后的一个演示应用显示了JMF在网络中的应用。如果需要,此演示能运行在一个独立的机器上,使用此机器即是传输方也是接收方。可是要观察到在网络中使用JMF的所有功能,你仍然需要至少两台联网的机器。
在23页中的Resources可下载Java 2平台,完整的源代码文件,以及其他一些完成本指南所需要的工具。
下载安装文件
将JMF安装到你的计算机中的第一步是在JMF的主页中下载安装文件,它同样包括了JMF源代码和API文档的链接。23页的Resources中有下载JMF的链接。
目前,JMF有Windows, Solaris, Linux等版本,以及可运行在任何装有虚拟机的计算机上一个纯Java版本。为了增加性能,你需要下载一个与你操作系统所适应的版本。任何在一个操作系统JMF版本下书写和编译的代码都可以方便的移植到另外的操作系统上。例如,如果你下载了一个Solaris版本的JMF并且编译了一个类,这些类就可以在Linux上使用,不会有任何问题。
作为选择,你可以选择下载纯Java版本,或者跨平台版本的JMF。这些版本没有使用操作系统特有的库文件。如果没有合适的JMF版本适合的操作系统,那么跨平台版本就是一个不错的选择。
安装JMF
下载完JMF安装程序后,双击安装程序的图标。
大部分安装程序都会有个选项,安装本地库到系统目录中;例如,Windows版本安装程序会有一个选项“Move DLLs to Windows/System directory.”。最好将此选项选中,因为它能确保这些操作系统的库文件能正确的安装
在安装的过程中,你还需要选择项目来更新系统的CLASSPATH和PATH变量。如果这些选项被关闭,那么在你编译和运行本指南的例程序的时候就需要在classpath中引入JMF的jar文件。
关于作者
Eric Olson在Retek Inc工作的软件工程师。它在Java平台上有四年的工作经验,并且在不同的基于Java的技术上富有经验,包括JMF, Jini, Jiro, JSP, servlets, and EJBs。Eric毕业于St. Paul, MN的St. Thomas大学,获得计算机科学的学位。他在IBM的SanFrancisco项目组工作,负责WebSphere商业组件。他同时再为Imation Corp.工作,负责存储应用。现在,他正在开发零售行业的基于web的软件解决方案。再业余的时间,Eric和Paul
Monday在Stereo Beacon上合作—一个分布式的点对点的基于JMF的媒体播放器。联系
Eric zpalffy@yahoo.com.
第二节. 一个简单的音频播放器
在本节中,我们将进行创建一个简单的音频播放器的第一个练习。本例将介绍Manager类和Player接口,中两个都是建立大多数基于JMF应用的重要部分。
本例的功能目标是在字符界面下播放本地的音频文件。我们将学习此源代码,并了解每一行所做的任务。完成本节后,你将会有一个基于JMF的可播放包括MP3, WAV, AU等多种音频文件的演示程序。
在本练习后的源代码分类种可查询文件SimpleAudioPlayer.java。
引入必要的类
SimpleAudioPlayer类中包括了一些调用,在其前几行中需要引入所有必要的类:
import javax.media.*;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.MalformedURLException;
The javax.media包是由JMF定义的多个包之一。javax.media是一个核心包,包括了定义Manager类和Player接口等。本节中,我们主要学习Manager类和Player接口,其余的javax.media类放在后面的章节中。
除了引入javax.media声明外,以上的代码片断引入了一些创建媒体播放器的输入的声明。
Player接口
在下面的代码片断中,创建一个公共类SimpleAudioPlayer并举例定义一个Player变量:
public class SimpleAudioPlayer {
private Player audioPlayer = null;
术语Player听起来由点熟悉,因为它是建立在我们公用的音频或者视频播放器的基础上的。事实上,这个接口的例子就像是当作它们的真实的副本。Players揭示了一个实体上的媒体播放器(如立体音箱系统或者VCR)涉及到功能上的方法。例如,一个JMF媒体播放器可以开始和结束一个媒体流。在本节种,我们将使用Player的开始和结束功能。
在一个文件上创建一个Player
使用JMF获得一个特定媒体文件的Player实例非常简单。Manager类在JMF中如同一个工厂制作许多的特殊接口类型,包括Player接口。因此,Manager类的责任就是创建Player实例,如下例:
public SimpleAudioPlayer(URL url) throws IOException,
NoPlayerException,
CannotRealizeException {
audioPlayer = Manager.createRealizedPlayer(url);
}
public SimpleAudioPlayer(File file) throws IOException,
NoPlayerException,
CannotRealizeException {
this(file.toURL());
}
如果你看完本节的代码,你可以注意到Manager类包含了创建一个Player实例的其他方法。我们会研究其中的一些,如在后面的章节中的DataSource或者MediaLocator的实例化。
Player的状态
JMF定义了大量的一个Player实例可能存在的不同状态。如下:
· Prefetched
· Prefetching
· Realized
· Realizing
· Started
· Unrealized
使用这些状态
因为使用媒体常常是资源非常密集的,由JMF对象揭示的许多方法都是不闭塞的,允许一系列事件监听的状态改变的异步通知。例如,一个Player在它可以启动之前,必须经过Prefetched和Realized状态。由于这些状态的改变都需要一些时间来完成,JMF媒体应用可以分配一个线程来初始化创建Player实例,然后再继续其他的操作。当Player准备就绪的时候,它会通知应用程序其状态已经改变。
在一个如同我们的这样简单的程序中,多功能性的类型并不是很重要。处于这个原因,Manager类也提供了一些创建Realized player的有用方法。调用一个createRealizedPlayer()方法来阻塞调用线程,直到player达到Realized状态。为了调用一个无阻塞的创建player的方法,我们在Manager类中使用了一个createPlayer()方法。下面的一行代码中创建了一个我们需要在例程序中使用的
Realized player:
audioPlayer = Manager.createRealizedPlayer(url);
启动和停止Player
设定一个Player实例的启动或是停止就如同调用Player的一个简单的认证方法,如下所示:
public void play() {
audioPlayer.start();
}
public void stop() {
audioPlayer.stop();
audioPlayer.close();
}
调用SimpleAudioPlayer类中的play()方法来实现调用Player实例的start()方法。调用此方法后,你能听到本地的喇叭的声音文件。同样的,stop()方法使player停止并且关闭掉Player对象。
对于读取和或者播放本地媒体文件来说,关闭Player实例释放所有资源是一个有用的方法。因为这是一个简单的例子,关闭Player是终止一个会话可接受的方法。但是在实际的应用中,你需要小心的确认在除掉Player之前必须要关闭掉。一但你已经关闭掉player,在再次播放一个媒体之前你必须要创建一个新的Player实例(等待它的状态改变)。
建立一个SimpleAudioPlayer
最后,这个媒体播放应用程序要包含一个可以从命令提示行中输入命令而调用的main()方法。在此main()方法中,我们将调用创建SimpleAudioPlayer的方法:
File audioFile = new File(args[0]);
SimpleAudioPlayer player = new SimpleAudioPlayer(audioFile);
在播放音频文件之前的唯一的一些事情就是调用已经创建的音频player的方法play(),如下所示:
player.play();
要停止和清除掉音频player,在main()方法中也应该有如下调用:
player.stop();
编译和运行SimpleAudioPlayer
通过在命令提示行输入javac SimpleAudioPlayer.java来编译例程序。所创建的文件SimpleAudioPlayer.class在当前工作目录中。
然后在命令提示行中键入如下命令来运行例程序:
java SimpleAudioPlayer audioFile
将audioFile替换成你本地机器上的音频文件。所有的相对文件名都试相对于当前的工作目录。你会看到一些当前正在播放文件的标志信息。要终止播放,按下回车键。
如果编译失败,确认JMF的jar文件已经正确的包含在CLASSPATH环境变量中。
第三节. JMF用户界面组件
播放视频
在前一节中,我们学习了建立一个通过字符界面播放音频文件的应用程序。JMF中一个最重要的特点就是你不需要为了配置媒体播放器而去了解媒体文件的格式;一切都内置了。举一个例子,再我们前面的例子中,需要使用MP3格式的时候,我们不需要让应用程序为一个MP3文件建立一个特殊的Player。
如同你将会再本节所见到的,对于视频文件的操作同样有效。JMF有所有媒体文件类型接口的详细资料。
处理视频媒体与音频最大的不同就是,我们必须建立一个能播放视频的显示屏幕。幸运的是,JMF能处理许多的这些资料。如同再上例一样我们会建立一个Player对象,并且使用很多的可视组件来直接从JMF对象中创建我们的可视的媒体浏览器。
本节中,我们将学习两个例程序。In this section, we'll walk through the second example application. 请再后面的练习的源代码分布中查阅MediaPlayerFrame.java。
关于例子
在本节中,我们将创建一个能显示和运行本地音频和视频媒体的应用程序。作为练习的一部分,我们将研究JMF内置的一些GUI组件。熟悉AWT和Swing将有助于你理解本例,但这并不是必须的。除非需要直接涉及到JMF的GUI组件,或者我们是不会详细介绍源代码的。你可以在源代码的注释中找到这里未涉及的详细说明。
本例中我们使用的许多概念,类和方法都和第一个例子的类似。建立Player的基本操作大都一样。最大的不同就是我们需要对Player对象专研更深一点,特别当需要从Player获取媒体信息的时候。
如何开始
视频播放器例子被设计得如同音频播放例子一样通过命令行来运行,但是本例需要建立在GUI基础上。如同在上节一样,我们先通过媒体文件名调用应用。然后,应用程序显示一个带有可操作媒体组件的窗体。
在MediaPlayerFrame开始的一行中我们定义了类并扩展自,javax.swing.Jframe类。这就是使媒体播放器如同一个在桌面上的单独窗体的方法。任何客户机程序创建了本媒体播放对象后都可以通过调用Jframe类中定义的show()方法来显示。
下面是一个MediaPlayerFrame正在播放MPEG电影的屏幕截图:
获取GUI组件
Player界面有一些方法来获取已选择可视组件的涉及。在MediaPlayerFrame中,我们使用如下组件:
· player.getVisualComponent()是一个播放所有视频媒体的可视组件。
· player.getControlPanelComponent() 是一个操作时间轴的可视组件(包括开始,停止,回放),也包含了一些媒体流的有用信息。
· player.getGainControl().getControlComponent() 是操作音量(增加)的可视组件。getGainControl()方法返回一个GainControl实例,可用于改变节目的增加等级。
使用可视化组件
上面的界面方法都返回一个java.awt.Component类的实例。没个实例都视可加载到我们窗体上的可视组件。这些组件都与Player有直接的联系,所以在这些组件上的所有可视元素的处理都会产生Player播放媒体后相应的变化。
在我们将这些组件加入到我们的窗体的之前,必须要保证它们不为空。因为并不是所有的媒体播放器包括每一种可视组件,我们只需添加相关播放器类型的组件。比如,一般来说一个音频播放器没有可视组件,所以getVisualComponent()就要返回空。你不会想在音频播放器窗体上添加可视组件的。
获得媒体的特殊控制
一个Player实例也可以通过getControl()和getControls()方法来暴露其控制,getControls()返回一个控制对象集,而getControl()返回一个控制。不同的播放器类型可选择为特殊的操作来暴露控制集去指定的媒体类型,或者用于获取该媒体的传输机制。如果你在写一个只支持某些媒体类型的播放器,你需要依靠某些在Player实例中可用Control对象。
由于我们的播放器是非常抽象的,被设计于播放多种不同媒体类型,我们简单的为用户暴露所有的Control对象。如果找到任何扩展的控制集,我们就可使用getControlComponent()方法来增加相应的可视控件到标签面板上。通过这个办法,用户就可以观察播放器上的所有组件。以下代码片断将所有的控制对象暴露给用户:
Control[] controls = player.getControls();
for (int i = 0; i < controls.length; i++) {
if (controls[i].getControlComponent() != null) {
tabPane.add(controls[i].getControlComponent());
}
}
为了使一个真实的应用程序能用Control实例做一些有用的事(除了能显示可视组件之外),应用程序需要知道该Control的特殊类型,并分配它。此后,应用程序就可使用这些control来控制媒体节目了。例如,如果你知道你经常使用的媒体暴露javax.media.control.QualityControl类型的Control,你能使用QualityControl界面,之后在QualityControl界面上通过调用各种方法来改变性质设定。
使用一个MediaLocator
在我们新的基于GUI的媒体播放器和我们的第一个简单播放器之间最大的不同就是,我们使用一个MediaLocator对象而不是URL来创建Player实例,如下所示:
public void setMediaLocator(MediaLocator locator) throws IOException,
NoPlayerException, CannotRealizeException {
setPlayer(Manager.createRealizedPlayer(locator));
}
我们将在稍后的章节中讨论这个变化的原因。目前,在网络上资源站点上,关于MediaLocator对象和URL的描述被认为是非常相似的。事实上,你可以从一个URL创建一个MediaLocator,也可以从MediaLocator获取到URL。我们的新媒体播放器一个URL中创建一个MediaLocator,并使用该MediaLocator通过文件创建了一个Player。
编译和运行MediaPlayerFrame
通过在命令提示行输入javac MediaPlayerFrame.java来编译例程序。在工作目录下将创建一个名为MediaPlayerFrame.class的文件。
在命令提示行中键入如下来运行例程序:
java MediaPlayerFrame mediaFile
你需要用你本机上的一个媒体文件来替换掉mediaFile(音频或者视频文件都可以)。所有的相对文件名都是相对于当前工作目录。你会看见一个显示控制媒体文件的GUI控制集的窗口。欲了解JMF支持的音频和视频文件列表,在23页的资源。
如果初始编译时失败,请确认JMF的jar文件已经包含在当前的CLASSPATH环境变量中。
MediaPlayerFrame在行动
在本节前你看见的一个视频播放器正在播放MPEG视频文件的屏幕截图。下面的屏幕截图显示了一个音频播放器正在播放一个MP3文件:
要更多的学习本练习中的例子,查看完成的MediaPlayerFrame源代码。
第四节. JMF概念
JMF体系结构
你曾见过了使用JMF播放本地媒体文件是多么的容易,现在我们将后退一步,来看看一幅是如何通过JMF创建了如此成熟的基于媒体的应用程序的大的画面,是如何通过JMF创建了如此成熟的基于媒体的应用程序。全面的了解JMF体系结构是没有意义的,本节将给你一个大体的概念,关于高级的JMF组件是如何组合起来创建想得到的东西。
JMF的组件结构非常的灵活,它的组件一般可以分成三个部分:
· Input描述某种被用于在进程休息的时候作为一个输入的媒体。
· process执行某些输入上的活动。一个过程有一个明确的输入和输出。大量的过程可用, 能被用于一个输入或者一批输入。这些过程能被联系起来,一个过程的输出被用于另外一个过程的输入。在这种风格中,大量的过程可能被应用于一个输入。(这段期间是可选择的——我们开始的两个例子没有包含真正的数据过程,只有一个来自文件的输入和一个通过Player的输出。)
· Output 描述了媒体的某些目的地。
从这些描述中,你可以想象到JMF组件体系结构听起来就好像在一个典型的立体声系统或者VCR之后。很容易设想到,使用JMF就如同打开电视或者在立体声音箱系统下调节声音的风格。例如,录制喜爱的电视节目的简单的动作能在这些组件的基础中:
· Input 是电视广播流,在同一个频道运输音频和视频。
· Process 是一个记录设备(就是,一个VCR或者许多的数字设备)转换模拟或者数字音频视频广播流成适合复制到磁带或其他媒体上的格式。
· Output 是记录已格式化轨迹(音频和视频)到某些类型的媒体上。
JMF资料处理模式
以下图片说明了JMF数据处理模块并对每个类型给出了例子:
使用此模式,很容易明白我们前面的两个例子,从文件中输入音频和视频并输出到本地计算机上。在后面的章节中,我们也会谈论一些通过传播和接收音频媒体的JMF网络功能。
处理模型例子
将JMF的输入,处理和输出模式联系起来,我们能开始想象许多基于媒体的操作都可能通过JMF完成。一个例子,转换一种媒体类型为其他类型并将其输出存储到一个新的文件。举一个例子,我们想要在不损坏原始文件的前提下转化一个WAV格式的音频文件为MP3格式。以下的过程模式插图,就是我们将开始执行转换的步骤:
本例的输入是一个WAV文件。它被一个媒体格式转换工具加工,并输出到一个新的文件。现在,让我们看看JMF API中的这个模式的每一步。我们使用输入,处理和输出模式作为概念上的路标。
JMF输入
再JMF中,一般由一个MediaLocator对象来描述一个输入。如先前规定的,
MediaLocator的外观和行为都非常象一个URL,这样它可以唯一确定网络上的一个资源。事实上,使用一个URL来创建一个MediaLocator是完全可能的;我们在前面的两个例子中就是这样做的。
为了我们的媒体转换例子,我们需要建立一个MediaLocator来描述最初的WAV文件。如同我们将在后面的章节中见到的,一个MediaLocator也可以用于描述一个跨越网络中媒体流。在这个案例中,MediaLocator会描述传播的URL――很像一个被URL指定的在Web上的资源,用于取代指定一个本地文件系统的文件来建立MediaLocator。
一个MediaLocator和一个URL之间的不同
要成功的建立一个URL对象,需要适当的java.net.URLStreamHandler安装于系统中。这个流处理的用途是能够处理被URL描述的流类型。一个MediaLocator对象并没有这个需要。例如,我们的下个应用程序将使用实时传输协议(RTP)在网络上传输音频。由于多数的系统都未为RTP协议安装一个URLStreamHandler,所以创建一个URL对象会失败。在这个应用中,只有MediaLocator对象会成功。
要理解更多关于URL对象以及创建和注册一个URLStreamHandler的信息,查阅JDK帮助文档(查看23页资源)。
JMF处理机
当我们使用JMF的时候,应用程序的处理机组件被Processor接口实例描述。你需要已有些熟悉Processor,它扩展至Player接口。由于Processor继承直Player接口,它同样也从Player继承所有可用属性。另外,Processor增加了两个属性:Configuring和Configured。这些扩展的属性(和与之关联的方法)用于Processor从输入流收集信息时的通信。
在我们的最后的例程序中,我们将建立一个Processor用于将MP3编码格式的音频转换成适合在网络上传播的格式。在稍后的板块中我们会讨论创建一个简单的Processor的步骤。
JMF输出
有少许的方法用于描述JMF中处理模式的输出状态。最简单的(并且我们将在最后一个例子中使用的)是javax.media.DataSink接口。一个DataSink读取媒体内容并且将其传送到一些目的地。本节中最开始的音频格式转换过程中,MP3(输出)文件将被DataSink描述。在我们最后一个例子中,我们将使用一个DataSink在实际上完成网络中传播音频媒体的工作。一个DataSink是在Manager类中,由指定一个DataSource(输入到DataSink)和一个MediaLocator(输出到DataSink)完成的。
一个DataSource实例描述可用于Players,Processors和DataSinks的输入数据。一个处理机的输出也被描述成一个DataSource对象。
这就是为什么处理器能彼此联系起来,在同一媒体数据中完成多种操作。这也是来自Processor的输出能作为输入被Player或者DataSink使用的原因(它可将媒体传递到输出目的地)。
一个DataSink的最后目的文件由一个MediaLocator对象说明。如同前面一样,MediaLocator描述一个网络资源;这就是媒体流将被传递的地方。
第五节.传播接收媒体
JMF和实时传输协议(RTP)
许多的友善网络的特征直接建立在JMF中,这些使为客户端程序通过网络传输和接收媒体非常容易。当在一个网络上的一个用户想要接收任何种类的媒体流的时候,它不需要在观看媒体前等待全部的广播下载到机器上;用户可以实时的观看广播。在流媒体中些提出了这个概念。通过流媒体,一个网络客户端能接收到其他机器上广播的音频,甚至获取正在发生的实况视频广播。
在IETF RFC 1889中定义了实时传输协议(RTP)。发展在快速和可靠的状态下通过网络传输时间极其敏感的数据,RTP在JMF中用于提供给用户向其他网络节点中传输媒体流的方法。
在本节中,我们将学习我们的最后一个例程序。这里,你将学习到如何传输一个存储在一台机器上的MP3文件到另外的在同一个网络的机器上去。实际的MP3源文件并不从主计算机上移除,它也不使复制到其他机器上去;事实上它将会转换成能使用RTP传输的文件格式并通过网络发送。一旦被一个客户端接收到,源文件(现在是RTP信息包的形式)可以再次传输,这一次是在接收机器上可播放的一种格式。
在MediaTransmitter.java文件中源代码查看学习以下练习。
设置处理模式
我们可以在前面的章节中定义的处理模式的基础下来讨论我们的最终的例子。在传输机器上,处理模式看起来像这样:
事实上,MediaTransmitter对象源代码包括了以下三行:
private MediaLocator mediaLocator = null;
private DataSink dataSink = null;
private Processor mediaProcessor = null;
这三个实例变量可以直接映射到前面的处理模式图表,如下:
· mediaProcessor变量是我们的处理器;它将负责转换音频文件从MP3文件模式到一个适合通过RTP协议传输的格式。
· dataSink变量是我们的输出块。
· 当我们建立DataSink时我们需要指定一个MediaLocator,它是DataSink的目的文件。
当我们通过运行DataSink我们的处理过的媒体,它将传输到我们在MediaLocator中指定的地点。
RTP MediaLocator
在前面的两个练习中,我们通过从文件中获得的一个URL建立了MediaLocator实例。 在本练习中,我们必须建立一个MediaLocator来描述网络上媒体传播输出流;换句话说,我们必须创建一个能我们的音频传播的目的地的MediaLocator。一个RTP MediaLocator符合如下规则,看起来就像一个典型的URL:
rtp://address:port/content-type
让我们看看上面URL规范的每一段:
· address 是将传输的媒体的地址。以单播的模式传输(一个专用IP地址),地址将会是有意接收的机器的IP地址。以广播的模式传播(到子网中的所有机器),地址将会是以255作为最后的一块的子网地址。举个例子,如果我再子网中可指定地址为192.168.1和想要传播到子网中的所有节点,我可以指定192.168.1.255作为地址;这样允许子网中的每个节点监听广播媒体。
· port 必须是被传输者和接收者都允许的一个端口。
· content-type 是媒体流类型。在我们的案子中,这个将会是音频。
下面的一个简单的RTP传播MediaLocator例子会让所有在指定网络中的机器接收到媒体流:
rtp://192.168.1.255:49150/audio
创建一个处理机
在setDataSource()方法中我们首先要做的就是创建一个Processor实例。
下面的Processor的职责是转换MP3音频媒体为一个RTP来表示:
public void setDataSource(DataSource ds) throws IOException,
NoProcessorException, CannotRealizeException, NoDataSinkException {
mediaProcessor = Manager.createRealizedProcessor(
new ProcessorModel(ds, FORMATS, CONTENT_DESCRIPTOR));
在Manager类中,我们能创建一个Processor对象,通过两种方法中的一种:
createProcessor()或者createRealizedProcessor()。你很可能会注意到这两个方法样式的显示和前面例子中创建一个Player的方法很相似。在目前的例子中,我们将创建一个已实现的Processor。我们这样做是因为我们使用的应用非常简单,在Processo处于Realized状态时我们不需要关心任何真实的工作。
创建一个ProcessorModel
创建一个已实现的Processor,我们需要创建一个为Processor描述输入和输出媒体类型的ProcessorModel实例。为了创建ProcessorModel,我们需要下面的一些:
· 一个DataSource,将被处理的媒体(输入文件)。
· 一个javax.media.Format数组,描述输入媒体的格式。
· 一个javax.media.protocol.ContentDescriptor实例,为我们的处理机描述输出格式。传送者的DataSource是通过一个参数传递到此方法。
定义输入和输出格式
因为我们的MediaTransmitter类会被时常用于将输入媒体格式(MP3)转换成一种输出格式(音频RTP),中学对象被定义成静态。我们创建一个新的javax.media.format.AudioFormat实例用于描述媒体输入类型(在java帮助文档中查看可用格式)。这就是我们的处理机可以获取MP3音频文件的原因。
我们也创建一个javax.media.protocol.ContentDescriptor实例来描述想要处理机输出的。在我们的案子中,这是一个RTP媒体流。
这就是为什么我们的处理机可以只制造RTP流。
下面的代码片断显示了我们如何设置格式和内容描述符变量,用于创建ProcessorModel对象:
private static final Format[] FORMATS = new Format[] {
new AudioFormat(AudioFormat.MPEG_RTP)};
private static final ContentDescriptor CONTENT_DESCRIPTOR =
new ContentDescriptor(ContentDescriptor.RAW_RTP);
连接输入,处理机和输出
现在我们有一个处于Realized状态的Processor,我们需要设置DataSink以能实际上传播RTP媒体。创建DataSink是简单的大概使用另外一个调用给Manager对象,如下所示:
dataSink = Manager.createDataSink(mediaProcessor.getDataOutput(),
mediaLocator);
createDataSink()方法获取新Processor的输出(作为一个DataSource参数)和MediaLocator对象,我们和MediaTransmitter对象同时建立的。通过这样,你能开始我们的不同的组件是如何在处理模式中联系起来的:我们从一个Processor中获取输出并使用他们作为输入到其他组件。在这个特殊的应用中,Processor输出用于传输媒体的DataSink的一个输入。
创建一个DataSource实例
在这点上,我们全部都是做和设置我们的媒体播放器的广播传输。
我们需要创建DataSource对象,我们用于创建处理机(就是,在我们的MediaTransmitter中,参数传递到setDataSource()方法)。下面是创建一个DataSource实例的代码:
File mediaFile = new File(args[1]);
DataSource source = Manager.createDataSource(new MediaLocator(
mediaFile.toURL()));
这段代码是在MediaTransmitter对象中的vmain()方法。这里我们通过从命令行输入的第二个参数创建一个File对象。我们通过文件创建一个MediaLocator,而后通过位置创建一个DataSource。这个新近创建的DataSource是一个涉及到传送者的输入文件。我们能使用这个DataSource初始化传输者。
开始和停止MediaTransmitter
我们通过调用其中的startTransmitting()方法来开始MediaTransmitter,如下所示:
public void startTransmitting() throws IOException {
mediaProcessor.start();
dataSink.open();
dataSink.start();
}
这个方法首先开启处理机,然后打开并启动DataSink。在这个调用后,接收机器就可在媒体传送者上监听。
停止传输者是非常简单的。以下代码将DataSink和Processor都停止和关闭掉:
public void stopTransmitting() throws IOException {
dataSink.stop();
dataSink.close();
mediaProcessor.stop();
mediaProcessor.close();
}
编译和运行MediaTransmitter
通过在命令行中输入javac MediaTransmitter.java来编译例程序,可在你的工作目录中生成一个同名的.class文件。
要运行例程序,在命令提示行中输入以下代码:
java MediaTransmitter rtpMediaLocator audioFile
此例将创建一个myAudio.mp3文件的媒体广播。不要忘记将rtpMediaLocator替换成一个媒体传输的RTP URL,如同先前讨论的。
你同样也需要将audioFile替换成你本机的音频文件名。
所有的相对文件名都是相对于当前工作目录的。你会看见一些信息标志正在播放的文件。按下Enter键来停止播放。
为传送者的一个例命令行交互如下:
java MediaTransmitter rtp://192.168.1.255:49150/audio myAudio.mp3
如果初始编辑失败,确定JMF的jar文件包含CLASSPATH环境变量中。要近一步探索本程序和练习,请查阅MediaTransmitter源代码。
接收传输的媒体
现在你可能会问,“如果没有人可以看或者收听的话,这个传播媒体有什么好的?”
幸运的是,设定一个接收传播媒体的客户端只需要对我们在第二个例程序的MediaPlayerFrame源代码做很小的改动。
MediaPlayerFrame类需要一个很小的调节来接收和播放音频文件。在main()方法中,你需要注释掉如下的一行:
mpf.setMediaLocator(new MediaLocator(new File(args[0]).toURL()));
并且输入如下的一行:
mpf.setMediaLocator(new MediaLocator(args[0]));
这个简单的改动允许我们通过String来创建一个MediaLocator对象,而不是通过创建一个File来创建MediaLocator。
其他代码都一样。
指定RTP URL
在12页的说明编译和运行MediaPlayerFrame介绍了如何编译和运行MediaPlayerFrame例程序。这唯一的不同就是你需要为传输者指定RTP URL。为接收者的例命令行交互如下:
java MediaPlayerFrame rtp://192.168.1.255:49150/audio
运行网络媒体传送者的注意事项
如果你在网络上只有权使用一台机器,你仍然可以运行传输程序。当你启动传送程序的时候,你可以即使用RTP URL传输地址,也可指定你工作的机器的机器地址。为了能够调节传输,在开始前接收者必须使用精确的同样的RTP URL。
如果你运行本例真实的网络版本,每台你使用的机器都需要安装JMF,不论是传输还是接收媒体流。这是必须的,因为不论是传送程序还是接收程序都大量的使用了JMF的API。
在任一个案子中,确认在指定的RTP URL中使用了相同的地址和端口;否则媒体传输是不会工作的。
第六节. 约束和资源
摘要
我希望本指南能给你提供如何使用JMF的API的有用的浏览。
我们建立了三个小的应用程序来播放本地的音频和视频,也通过网络传播和接收媒体。这些应用程序的源代码中包含了很多的javadoc样式的注释。这就有助于你理解你剩余的问题。
许多JMF的主题在本指南中并没有涉及。实际上,我们更关注JMF的基本概念和应用;在此基础上,我们能轻易地扩展学习的其他范围。要更深入JMF的应用程序,你可能想要学习下面的面板中所提到的主题。更近一步的阅读本指南中的主题,查阅23页的资源。
高级主题
大量的值得做的练习在本指南的范围之上。在简单的说明之下自己更进一步的学习,你可以扩展我们的应用程序代码,也可以反展你的JMF相关知识。使用以下的练习开始:
· 媒体捕获:JMF包含了丰富的API来捕获媒体数据。如果你对使用JMF捕获媒体感兴趣,你可以使用javax.media.CaptureDeviceManager类和javax.media.protocol.CaptureDevice接口的API来学习。对于一个高级的练习,考虑使用CaptureDeviceManager和CaptureDevice接口来增加媒体捕获功能到媒体播放应用程序的GUI版本上。
· 会话管理:由于本指南是一个JMF的说明,我们使输出表现非常的简单,仅仅实现了javax.media.DataSink输出。
另外的输出表示是使用javax.media.rtp.SessionManager。这个管理类允许客户端创建并监视他们的RTP流和连接。通过SessionManager并随后创建流,它可能非常的接近监视RTP会话。作为一个高级的练习,转换我们的地三个演示程序来使用SessionManager,然后监听流出的RTP流已经哪些客户端在收听。
· 使用JMF的多点传送:我们的广播演示应用程序说明了如何传送一个网络的媒体到另外一个网络的一或多台机器上去。它也可能使用JMF中的多点传输协议来提供给更复杂,多用户的网络。
JMF用户指南提供了一个使用JMF的多播协议的更深入的探讨。更进一步追踪本主题查看23页资源。
· 传输视频: 我们的最后一个演示应用程序着眼于如何传输一个MP3音频文件,但是JMF也能够通过网络传递视频。关注API文档中的Format和ContentDescriptor类获得如何使用的更好的方法。
· 导入/导出RTP媒体流: JMF同样允许将RTP流保存为文件以便将来使用。举一个实例,一个远程电信会议可以保存下来以后再看。
由于流已经保存再RTP格式中,已经不需要再次转换,这样可导致传输程序的性能改进。通过一个文件而不是URL来设置DataSink对象中输入/输出MediaLocator。你会再JMF用户指南中发现更深层次的主题探讨。
资源
JMF
· 下载mediaplayer.jar,本指南中使用的完整的例源代码。
· JMF主页 (http://www.javasoft.com/jmf)是最好的探讨JMF更多信息的资源。
· 你可以找到JMF说明书(http://java.sun.com/products/java-media/jmf/2.1.1/specdownload.html),再Java开发者联盟上包括API文档和JMF用户指南。你必须有权使用所有的这些资源,如果你想做任何更深入的JMF编程的话。
· 官方的JMF支持文件格式 页面
(http://java.sun.com/products/java-media/jmf/2.1.1/formats.html) 列出了所有可为JMF辨识并播放的文件格式。此文件格式页面也包括了学习更多关于捕获设备和RTP格式的参考。
· MPEG-4 Video for JMF (http://www.alphaworks.ibm.com/tech/mpeg-4), 来自IBM
alphaWorks, 是一个JMF的视频编解码器。
RTP
· IETF RTP RFC (http://www.ietf.org/rfc/rfc1889.txt) 非常详细的描述了RTP协议。
· 查看 JMF API Guide
(http://java.sun.com/products/java-media/jmf/2.1.1/specdownload.html) ,有许多有关于RTP协议和描述以及它是如何在JMF上应用的。
· 哥伦比亚大学有一个比较有用的RTP FAQ(http://www.cs.columbia.edu/~hgs/rtp/faq.html).
Java技术
· Java 2 Platform, Standard Edition (http://java.sun.com/j2se/) 可从sun公司获得。
· 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) 是非常好的能学习到很多关于Java程序语言中GUI编程的好地方。
· 另外一个sun指南学习network programming 基础
(http://java.sun.com/docs/books/tutorial/networking/index.html)。
多点传输协议
· Explicit Multicast (XCAST)
(http://oss.software.ibm.com/developerworks/opensource/xcast/) 是IP多点传输的一种形式,为非常多的多点传输组设计提供可升级的支持,这些组有些少量的参与者代表。XCAST 代码得到了IBM Common Public License的认可。
· Todd Montgomery 的 MTP page (http://www.nard.net/~tmont/rm-links.html),
在这里你能找到一个广泛的涉及到多点传输协议的列表。
附加资源
· 你可以在
developerWorks Java technology zone (http://www-106.ibm.com/developerworks/java/)中找到许多的关于Java各方面的内容。
· 查看 developerWorks tutorials page
(http://www-105.ibm.com/developerworks/education.nsf/dw/java-onlinecourse-bytitle?OpenDocument&Count=for a complete listing of free tutorials.
Linux的chattr与lsattr命令详解
PS:有时候你发现用root权限都不能修改某个文件,大部分原因是曾经用chattr命令锁定该文件了。chattr命令的作用很大,其中一些功能是由Linux内核版本来支持的,不过现在生产绝大部分跑的linux系统都是2.6以上内核了。通过chattr命令修改属性能够提高系统的安全性,但是它并不适合所有的目录。chattr命令不能保护/、/dev、/tmp、/var目录。lsattr命令是显示chattr命令设置的文件属性。
这两个命令是用来查看和改变文件、目录属性的,与chmod这个命令相比,chmod只是改变文件的读写、执行权限,更底层的属性控制是由chattr来改变的。
chattr命令的用法:chattr [ -RVf ] [ -v version ] [ mode ] files…
最关键的是在[mode]部分,[mode]部分是由+-=和[ASacDdIijsTtu]这些字符组合的,这部分是用来控制文件的
属性。
+ :在原有参数设定基础上,追加参数。
- :在原有参数设定基础上,移除参数。
= :更新为指定参数设定。
A:文件或目录的 atime (access time)不可被修改(modified), 可以有效预防例如手提电脑磁盘I/O错误的发生。
S:硬盘I/O同步选项,功能类似sync。
a:即append,设定该参数后,只能向文件中添加数据,而不能删除,多用于服务器日志文件安全,只有root才能设定这个属性。
c:即compresse,设定文件是否经压缩后再存储。读取时需要经过自动解压操作。
d:即no dump,设定文件不能成为dump程序的备份目标。
i:设定文件不能被删除、改名、设定链接关系,同时不能写入或新增内容。i参数对于文件 系统的安全设置有很大帮助。
j:即journal,设定此参数使得当通过mount参数:data=ordered 或者 data=writeback 挂 载的文件系统,文件在写入时会先被记录(在journal中)。如果filesystem被设定参数为 data=journal,则该参数自动失效。
s:保密性地删除文件或目录,即硬盘空间被全部收回。
u:与s相反,当设定为u时,数据内容其实还存在磁盘中,可以用于undeletion。
各参数选项中常用到的是a和i。a选项强制只可添加不可删除,多用于日志系统的安全设定。而i是更为严格的安全设定,只有superuser (root) 或具有CAP_LINUX_IMMUTABLE处理能力(标识)的进程能够施加该选项。
应用举例:
1、用chattr命令防止系统中某个关键文件被修改:
# chattr +i /etc/resolv.conf
然后用mv /etc/resolv.conf等命令操作于该文件,都是得到Operation not permitted 的结果。vim编辑该文件时会提示W10: Warning: Changing a readonly file错误。要想修改此文件就要把i属性去掉: chattr -i /etc/resolv.conf
# lsattr /etc/resolv.conf
会显示如下属性
----i-------- /etc/resolv.conf
2、让某个文件只能往里面追加数据,但不能删除,适用于各种日志文件:
# chattr +a /var/log/messages
Java编程规则
(1) 类名首字母应该大写。字段、方法以及对象(句柄)的首字母应小写。对于所有标识符,其中包含的所有单词都应紧靠在一起,而且大写中间单词的首字母。例如:
ThisIsAClassName
thisIsMethodOrFieldName
若在定义中出现了常数初始化字符,则大写static final基本类型标识符中的所有字母。这样便可标志出它们属于编译期的常数。
Java包(Package)属于一种特殊情况:它们全都是小写字母,即便中间的单词亦是如此。对于域名扩展名称,如com,org,net或者edu等,全部都应小写(这也是Java 1.1和Java 1.2的区别之一)。
(2) 为了常规用途而创建一个类时,请采取“经典形式”,并包含对下述元素的定义:
equals()
hashCode()
toString()
clone()(implement Cloneable)
implement Serializable
(3) 对于自己创建的每一个类,都考虑置入一个main(),其中包含了用于测试那个类的代码。为使用一个项目中的类,我们没必要删除测试代码。若进行了任何形式的改动,可方便地返回测试。这些代码也可作为如何使用类的一个示例使用。
(4) 应将方法设计成简要的、功能性单元,用它描述和实现一个不连续的类接口部分。理想情况下,方法应简明扼要。若长度很大,可考虑通过某种方式将其分割成较短的几个方法。这样做也便于类内代码的重复使用(有些时候,方法必须非常大,但它们仍应只做同样的一件事情)。
(5) 设计一个类时,请设身处地为客户程序员考虑一下(类的使用方法应该是非常明确的)。然后,再设身处地为管理代码的人考虑一下(预计有可能进行哪些形式的修改,想想用什么方法可把它们变得更简单)。
(6) 使类尽可能短小精悍,而且只解决一个特定的问题。下面是对类设计的一些建议:
■一个复杂的开关语句:考虑采用“多形”机制
■数量众多的方法涉及到类型差别极大的操作:考虑用几个类来分别实现
■许多成员变量在特征上有很大的差别:考虑使用几个类
(7) 让一切东西都尽可能地“私有”——private。可使库的某一部分“公共化”(一个方法、类或者一个字段等等),就永远不能把它拿出。若强行拿出,就可能破坏其他人现有的代码,使他们不得不重新编写和设计。若只公布自己必须公布的,就可放心大胆地改变其他任何东西。在多线程环境中,隐私是特别重要的一个因素——只有private字段才能在非同步使用的情况下受到保护。
(8) 谨惕“巨大对象综合症”。对一些习惯于顺序编程思维、且初涉OOP领域的新手,往往喜欢先写一个顺序执行的程序,再把它嵌入一个或两个巨大的对象里。根据编程原理,对象表达的应该是应用程序的概念,而非应用程序本身。
(9) 若不得已进行一些不太雅观的编程,至少应该把那些代码置于一个类的内部。
(10) 任何时候只要发现类与类之间结合得非常紧密,就需要考虑是否采用内部类,从而改善编码及维护工作。
(11) 尽可能细致地加上注释,并用javadoc注释文档语法生成自己的程序文档。
(12) 避免使用“魔术数字”,这些数字很难与代码很好地配合。如以后需要修改它,无疑会成为一场噩梦,因为根本不知道“100”到底是指“数组大小”还是“其他全然不同的东西”。所以,我们应创建一个常数,并为其使用具有说服力的描述性名称,并在整个程序中都采用常数标识符。这样可使程序更易理解以及更易维护。
(13) 涉及构建器和异常的时候,通常希望重新丢弃在构建器中捕获的任何异常——如果它造成了那个对象的创建失败。这样一来,调用者就不会以为那个对象已正确地创建,从而盲目地继续。
(14) 当客户程序员用完对象以后,若你的类要求进行任何清除工作,可考虑将清除代码置于一个良好定义的方法里,采用类似于cleanup()这样的名字,明确表明自己的用途。除此以外,可在类内放置一个boolean(布尔)标记,指出对象是否已被清除。在类的finalize()方法里,请确定对象已被清除,并已丢弃了从RuntimeException继承的一个类(如果还没有的话),从而指出一个编程错误。在采取象这样的方案之前,请确定finalize()能够在自己的系统中工作(可能需要调用System.runFinalizersOnExit(true),从而确保这一行为)。
(15) 在一个特定的作用域内,若一个对象必须清除(非由垃圾收集机制处理),请采用下述方法:初始化对象;若成功,则立即进入一个含有finally从句的try块,开始清除工作。
(16) 若在初始化过程中需要覆盖(取消)finalize(),请记住调用super.finalize()(若Object属于我们的直接超类,则无此必要)。在对finalize()进行覆盖的过程中,对super.finalize()的调用应属于最后一个行动,而不应是第一个行动,这样可确保在需要基础类组件的时候它们依然有效。
(17) 创建大小固定的对象集合时,请将它们传输至一个数组(若准备从一个方法里返回这个集合,更应如此操作)。这样一来,我们就可享受到数组在编译期进行类型检查的好处。此外,为使用它们,数组的接收者也许并不需要将对象“造型”到数组里。
(18) 尽量使用interfaces,不要使用abstract类。若已知某样东西准备成为一个基础类,那么第一个选择应是将其变成一个interface(接口)。只有在不得不使用方法定义或者成员变量的时候,才需要将其变成一个abstract(抽象)类。接口主要描述了客户希望做什么事情,而一个类则致力于(或允许)具体的实施细节。
(19) 在构建器内部,只进行那些将对象设为正确状态所需的工作。尽可能地避免调用其他方法,因为那些方法可能被其他人覆盖或取消,从而在构建过程中产生不可预知的结果。
(20) 对象不应只是简单地容纳一些数据;它们的行为也应得到良好的定义。
(21) 在现成类的基础上创建新类时,请首先选择“新建”或“创作”。只有自己的设计要求必须继承时,才应考虑这方面的问题。若在本来允许新建的场合使用了继承,则整个设计会变得没有必要地复杂。
(22) 用继承及方法覆盖来表示行为间的差异,而用字段表示状态间的区别。一个非常极端的例子是通过对不同类的继承来表示颜色,这是绝对应该避免的:应直接使用一个“颜色”字段。
(23) 为避免编程时遇到麻烦,请保证在自己类路径指到的任何地方,每个名字都仅对应一个类。否则,编译器可能先找到同名的另一个类,并报告出错消息。若怀疑自己碰到了类路径问题,请试试在类路径的每一个起点,搜索一下同名的.class文件。
(24) 在Java 1.1 AWT中使用事件“适配器”时,特别容易碰到一个陷阱。若覆盖了某个适配器方法,同时拼写方法没有特别讲究,最后的结果就是新添加一个方法,而不是覆盖现成方法。然而,由于这样做是完全合法的,所以不会从编译器或运行期系统获得任何出错提示——只不过代码的工作就变得不正常了。
(25) 用合理的设计方案消除“伪功能”。也就是说,假若只需要创建类的一个对象,就不要提前限制自己使用应用程序,并加上一条“只生成其中一个”注释。请考虑将其封装成一个“独生子”的形式。若在主程序里有大量散乱的代码,用于创建自己的对象,请考虑采纳一种创造性的方案,将些代码封装起来。
(26) 警惕“分析瘫痪”。请记住,无论如何都要提前了解整个项目的状况,再去考察其中的细节。由于把握了全局,可快速认识自己未知的一些因素,防止在考察细节的时候陷入“死逻辑”中。
(27) 警惕“过早优化”。首先让它运行起来,再考虑变得更快——但只有在自己必须这样做、而且经证实在某部分代码中的确存在一个性能瓶颈的时候,才应进行优化。除非用专门的工具分析瓶颈,否则很有可能是在浪费自己的时间。性能提升的隐含代价是自己的代码变得难于理解,而且难于维护。
(28) 请记住,阅读代码的时间比写代码的时间多得多。思路清晰的设计可获得易于理解的程序,但注释、细致的解释以及一些示例往往具有不可估量的价值。无论对你自己,还是对后来的人,它们都是相当重要的。如对此仍有怀疑,那么请试想自己试图从联机Java文档里找出有用信息时碰到的挫折,这样或许能将你说服。
(29) 如认为自己已进行了良好的分析、设计或者实施,那么请稍微更换一下思维角度。试试邀请一些外来人士——并不一定是专家,但可以是来自本公司其他部门的人。请他们用完全新鲜的眼光考察你的工作,看看是否能找出你一度熟视无睹的问题。采取这种方式,往往能在最适合修改的阶段找出一些关键性的问题,避免产品发行后再解决问题而造成的金钱及精力方面的损失。
(30) 良好的设计能带来最大的回报。简言之,对于一个特定的问题,通常会花较长的时间才能找到一种最恰当的解决方案。但一旦找到了正确的方法,以后的工作就轻松多了,再也不用经历数小时、数天或者数月的痛苦挣扎。我们的努力工作会带来最大的回报(甚至无可估量)。而且由于自己倾注了大量心血,最终获得一个出色的设计方案,成功的快感也是令人心动的。坚持抵制草草完工的诱惑——那样做往往得不偿失。
(31) 可在Web上找到大量的编程参考资源,甚至包括大量新闻组、讨论组、邮寄列表等。
MyEclipse 快捷键
(1)Ctrl+M切换窗口的大小
(2)Ctrl+Q跳到最后一次的编辑处
(3)F2当鼠标放在一个标记处出现Tooltip时候按F2则把鼠标移开时Tooltip还会显示即Show Tooltip Description。
F3跳到声明或定义的地方。
F5单步调试进入函数内部。
F6单步调试不进入函数内部,如果装了金山词霸2006则要把“取词开关”的快捷键改成其他的。
F7由函数内部返回到调用处。
F8一直执行到下一个断点。
(4)Ctrl+Pg~对于XML文件是切换代码和图示窗口
(5)Ctrl+Alt+I看Java文件中变量的相关信息
(6)Ctrl+PgUp对于代码窗口是打开“Show List”下拉框,在此下拉框里显示有最近曾打开的文件
(7)Ctrl+/ 在代码窗口中是这种//~注释。
Ctrl+Shift+/ 在代码窗口中是这种/*~*/注释,在JSP文件窗口中是<!--~-->。
(8)Alt+Shift+O(或点击工具栏中的Toggle Mark Occurrences按钮) 当点击某个标记时可使本页面中其他地方的此标记黄色凸显,并且窗口的右边框会出现白色的方块,点击此方块会跳到此标记处。
(9)右击窗口的左边框即加断点的地方选Show Line Numbers可以加行号。
(10)Ctrl+I格式化激活的元素Format Active Elements。
Ctrl+Shift+F格式化文件Format Document。
(11)Ctrl+S保存当前文件。
Ctrl+Shift+S保存所有未保存的文件。
(12)Ctrl+Shift+M(先把光标放在需导入包的类名上) 作用是加Import语句。
Ctrl+Shift+O作用是缺少的Import语句被加入,多余的Import语句被删除。
(13)Ctrl+Space提示键入内容即Content Assist,此时要将输入法中Chinese(Simplified)IME-Ime/Nonlme Toggle的快捷键(用于切换英文和其他文字)改成其他的。
Ctrl+Shift+Space提示信息即Context Information。
(14)双击窗口的左边框可以加断点。
(15)Ctrl+D删除当前行。
Alt+↓ 当前行和下面一行交互位置(特别实用,可以省去先剪切,再粘贴了)
Alt+↑ 当前行和上面一行交互位置(同上)
Alt+← 前一个编辑的页面
Alt+→ 下一个编辑的页面(当然是针对上面那条来说了)
Alt+Enter 显示当前选择资源(工程,or 文件 or文件)的属性
Shift+Enter 在当前行的下一行插入空行(这时鼠标可以在当前行的任一位置,不一定是最后)
Shift+Ctrl+Enter 在当前行插入空行(原理同上条)
Ctrl+Q 定位到最后编辑的地方
Ctrl+L 定位在某行 (对于程序超过100的人就有福音了)
Ctrl+M 最大化当前的Edit或View (再按则反之)
Ctrl+/ 注释当前行,再按则取消注释
Ctrl+O 快速显示 OutLine
Ctrl+T 快速显示当前类的继承结构
Ctrl+W 关闭当前Editer
Ctrl+K 参照选中的Word快速定位到下一个
Ctrl+E 快速显示当前Editer的下拉列表(如果当前页面没有显示的用黑体表示)
Ctrl+/(小键盘) 折叠当前类中的所有代码
Ctrl+×(小键盘) 展开当前类中的所有代码
Ctrl+Space 代码助手完成一些代码的插入(但一般和输入法有冲突,可以修改输入法的热键,也可以暂用Alt+/来代替)
Ctrl+Shift+E 显示管理当前打开的所有的View的管理器(可以选择关闭,激活等操作)
Ctrl+J 正向增量查找(按下Ctrl+J后,你所输入的每个字母编辑器都提供快速匹配定位到某个单词,如果没有,则在stutes line中显示没有找到了,查一个单词时,特别实用,这个功能Idea两年前就有了)
Ctrl+Shift+J 反向增量查找(和上条相同,只不过是从后往前查)
Ctrl+Shift+F4 关闭所有打开的Editer
Ctrl+Shift+X 把当前选中的文本全部变味小写
Ctrl+Shift+Y 把当前选中的文本全部变为小写
Ctrl+Shift+F 格式化当前代码
Ctrl+Shift+P 定位到对于的匹配符(譬如{}) (从前面定位后面时,光标要在匹配符里面,后面到前面,则反之)
下面的快捷键是重构里面常用的,本人就自己喜欢且常用的整理一下(注:一般重构的快捷键都是Alt+Shift开头的了)
Alt+Shift+R 重命名 (是我自己最爱用的一个了,尤其是变量和类的Rename,比手工方法能节省很多劳动力)
Alt+Shift+M 抽取方法 (这是重构里面最常用的方法之一了,尤其是对一大堆泥团代码有用)
Alt+Shift+C 修改函数结构(比较实用,有N个函数调用了这个方法,修改一次搞定)
Alt+Shift+L 抽取本地变量( 可以直接把一些魔法数字和字符串抽取成一个变量,尤其是多处调用的时候)
Alt+Shift+F 把Class中的local变量变为field变量 (比较实用的功能)
Alt+Shift+I 合并变量(可能这样说有点不妥Inline)
Alt+Shift+V 移动函数和变量(不怎么常用)
Alt+Shift+Z 重构的后悔药(Undo)
Eclipse快捷键大全
Ctrl+1 快速修复(最经典的快捷键,就不用多说了)
Ctrl+D: 删除当前行
Ctrl+Alt+↓ 复制当前行到下一行(复制增加)
Ctrl+Alt+↑ 复制当前行到上一行(复制增加)